"sys.monitoring" --- 実行イベントモニタリング
*********************************************

Added in version 3.12.

======================================================================

注釈:

  "sys.monitoring" は "sys" モジュール内の名前空間で、独立したモジュー
  ルではありません。 "import sys.monitoring" は "ModuleNotFoundError"
  で失敗します。 代わりに "import sys" を実行し、"sys.monitoring" を使
  ってください。

この名前空間は、イベントモニタリングの有効化と制御に必要な関数と定数へ
のアクセスを提供します。

プログラムの実行中には、実行を監視するツールが関心を持つさまざまなイベ
ントが発生します。 "sys.monitoring" 名前空間は、対象のイベントが発生し
たときにコールバックを受け取る手段を提供します。

モニタリング API は 3 つの要素から構成されます:

* ツール識別子

* イベント

* コールバック


ツール識別子
============

ツール識別子は、整数とそれに関連付けられた名前からなります。 ツール識
別子を使うことで、ツール同士の干渉を抑え、複数のツールが同時に動作でき
るようにします。 現在、ツールは完全に独立しており、互いを監視すること
はできません。 この制約は将来なくなる可能性があります。

イベントを登録または有効化する前に、ツールは識別子を選ぶ必要があります
。 識別子は 0 から 5 までの整数です。


ツールの登録と使用
------------------

sys.monitoring.use_tool_id(tool_id: int, name: str, /) -> None

   *tool_id* を使う前に呼び出す必要があります。 *tool_id* は 0 から 5
   までの整数でなければなりません。 *tool_id* が使用中なら
   "ValueError" を送出します。

sys.monitoring.clear_tool_id(tool_id: int, /) -> None

   *tool_id* に関連付けられたすべてのイベントとコールバック関数の登録
   を解除します。

   Added in version 3.14.

sys.monitoring.free_tool_id(tool_id: int, /) -> None

   ツールで *tool_id* が不要になったら呼び出してください。 *tool_id*
   を解放する前に "clear_tool_id()" を呼び出します。

   バージョン 3.14 で変更: *tool_id* を解放する前に "clear_tool_id()"
   を呼び出すようになりました。 以前は、*tool_id* に関連付けられたグロ
   ーバルイベントやローカルイベントを無効にせず、コールバック関数の登
   録も解除していませんでした。

sys.monitoring.get_tool(tool_id: int, /) -> str | None

   *tool_id* が使用中ならツール名を返し、そうでなければ "None" を返し
   ます。 *tool_id* は 0 から 5 までの整数でなければなりません。

VM はイベントについてすべての ID を同じように扱いますが、ツール間の協
調を容易にするため、次の ID があらかじめ定義されています。

   sys.monitoring.DEBUGGER_ID = 0
   sys.monitoring.COVERAGE_ID = 1
   sys.monitoring.PROFILER_ID = 2
   sys.monitoring.OPTIMIZER_ID = 5


イベント
========

次のイベントをサポートしています:

sys.monitoring.events.BRANCH_LEFT

   条件分岐が左に進む。

   「左」と「右」の分岐をどのように示すかはツールに任されています。 ど
   ちらの分岐が「左」で、どちらが「右」になるかは保証されませんが、プ
   ログラムの実行中に対応が変わることはありません。

sys.monitoring.events.BRANCH_RIGHT

   条件分岐が右に進む。

sys.monitoring.events.CALL

   Python コードでの呼び出し (イベントは呼び出しの前に発生)。

sys.monitoring.events.C_RAISE

   Python 関数以外の呼び出し可能オブジェクトからの例外の送出 (イベント
   は呼び出しの終了後に発生)。

sys.monitoring.events.C_RETURN

   Python 関数以外の呼び出し可能オブジェクトからのリターン (イベントは
   リターン後に発生)。

sys.monitoring.events.EXCEPTION_HANDLED

   例外が処理される。

sys.monitoring.events.INSTRUCTION

   VM 命令が実行されようとしている。

sys.monitoring.events.JUMP

   制御フローグラフで無条件ジャンプが行われる。

sys.monitoring.events.LINE

   直前の命令とは異なる行番号を持つ命令が実行されようとしている。

sys.monitoring.events.PY_RESUME

   Python 関数の再開 (ジェネレーター関数やコルーチン関数の場合)。 ただ
   し "throw()" の呼び出しは除く。

sys.monitoring.events.PY_RETURN

   Python 関数からのリターン (リターンの直前に発生し、呼び出された関数
   のフレームはスタック上にある)。

sys.monitoring.events.PY_START

   Python 関数の開始 (呼び出しの直後に発生し、呼び出された関数のフレー
   ムはスタック上にある)。

sys.monitoring.events.PY_THROW

   "throw()" の呼び出しによって Python 関数が再開される。

sys.monitoring.events.PY_UNWIND

   例外によるスタックの巻き戻し中に Python 関数を抜ける。 関数内で直接
   送出され、そのまま外部へ伝播する例外も含む。

sys.monitoring.events.PY_YIELD

   Python 関数からの yield (yield の直前に発生し、呼び出された関数のフ
   レームはスタック上にある)。

sys.monitoring.events.RAISE

   例外が送出される。 ただし "STOP_ITERATION" イベントを発生させるもの
   は除く。

sys.monitoring.events.RERAISE

   例えば "finally" ブロックの末尾で、例外が再送出される。

sys.monitoring.events.STOP_ITERATION

   擬似的な "StopIteration" が送出される。 STOP_ITERATION イベント を
   参照。

将来、イベントが追加される可能性があります。

これらのイベントは "sys.monitoring.events" 名前空間の属性です。 各イベ
ントは 2 の累乗の整数定数で表されます。 イベントの集合を定義するには、
個々のイベントのビット論理和を取ります。 例えば "PY_RETURN" と
"PY_START" の両方を指定するには、"PY_RETURN | PY_START" という式を使い
ます。

sys.monitoring.events.NO_EVENTS

   "0" の別名で、次のように明示的に比較できます。

      if get_events(DEBUGGER_ID) == NO_EVENTS:
          ...

   このイベントを設定すると、すべてのイベントを無効にします。


ローカルイベント
----------------

ローカルイベントはプログラムの通常の実行に関連し、明確に定められた位置
で発生します。 すべてのローカルイベントは位置ごとに無効にできます。 ロ
ーカルイベントには次のものがあります:

* "PY_START"

* "PY_RESUME"

* "PY_RETURN"

* "PY_YIELD"

* "CALL"

* "LINE"

* "INSTRUCTION"

* "JUMP"

* "BRANCH_LEFT"

* "BRANCH_RIGHT"

* "STOP_ITERATION"


非推奨のイベント
----------------

* "BRANCH"

"BRANCH" イベントは 3.14 で非推奨になりました。 "BRANCH_LEFT" と
"BRANCH_RIGHT" は個別に無効にできるため、これらを使うとパフォーマンス
が大幅に向上します。


付随するイベント
----------------

付随するイベントもほかのイベントと同じように監視できますが、別のイベン
トによって制御されます:

* "C_RAISE"

* "C_RETURN"

"C_RETURN" と "C_RAISE" は "CALL" によって制御されます。 "C_RETURN" と
"C_RAISE" を受け取れるのは、対応する "CALL" を監視している場合だけです
。


その他のイベント
----------------

その他のイベントは、必ずしもプログラム内の特定の位置に結び付いておらず
、位置ごとに個別に無効にすることはできません。

監視できるその他のイベントは次のとおりです:

* "PY_THROW"

* "PY_UNWIND"

* "RAISE"

* "EXCEPTION_HANDLED"

* "RERAISE"

バージョン 3.15 で変更: その他のイベントも、コードオブジェクト単位で有
効・無効にできるようになりました。 コールバックから "DISABLE" を返すと
、現在のツールについて、そのコードオブジェクト全体でイベントを無効にし
ます。


STOP_ITERATION イベント
-----------------------

**PEP 380** では、ジェネレーターやコルーチンから値を返すときに
"StopIteration" 例外を送出すると定めています。 ただし、この方法で値を
返すのは非常に非効率です。 そのため、一部の Python 実装、特に CPython
3.12 以降では、ほかのコードから見える場合を除いて例外を送出しません。

ジェネレーターやコルーチンを遅くせずに実際の例外を監視できるよう、
"STOP_ITERATION" イベントを用意しています。 "STOP_ITERATION" はローカ
ルに無効にできます。

"STOP_ITERATION" イベントと、"StopIteration" 例外に対する "RAISE" イベ
ントは同等で、イベントの生成時には互いに置き換えられるものとして扱われ
ます。 実装はパフォーマンス上の理由で "STOP_ITERATION" を優先しますが
、"StopIteration" を伴う "RAISE" イベントを生成する場合もあります。


イベントの有効化と無効化
========================

イベントを監視するには、そのイベントを有効にし、対応するコールバックを
登録する必要があります。 イベントはグローバルに、特定のコードオブジェ
クトに対して、またはその両方で設定して、有効・無効にできます。 グロー
バルとローカルの両方で有効にしても、イベントは 1 回だけ発生します。


イベントのグローバルな設定
--------------------------

監視するイベントの集合を変更することで、イベントをグローバルに制御でき
ます。

sys.monitoring.get_events(tool_id: int, /) -> int

   有効なすべてのイベントを表す "int" を返します。

sys.monitoring.set_events(tool_id: int, event_set: int, /) -> None

   *event_set* に指定されたすべてのイベントを有効にします。 *tool_id*
   が使用中でなければ "ValueError" を送出します。

デフォルトでは、有効なイベントはありません。


コードオブジェクトごとのイベント
--------------------------------

Events can also be controlled on a per code object basis. The
functions defined below which accept a "types.CodeType" should be
prepared to accept a look-alike object from functions which are not
defined in Python (see モニタリング C API).

sys.monitoring.get_local_events(tool_id: int, code: CodeType, /) -> int

   *code* のすべての ローカルイベント を返します。

sys.monitoring.set_local_events(tool_id: int, code: CodeType, event_set: int, /) -> None

   *event_set* に指定された、*code* のすべての ローカルイベント を有効
   にします。 *tool_id* が使用中でなければ "ValueError" を送出します。


イベントの無効化
----------------

sys.monitoring.DISABLE

   コールバック関数から返すことで、現在のコード位置でのイベントを無効
   にする特殊な値です。

コールバック関数から "sys.monitoring.DISABLE" を返すと、特定のコード位
置での ローカルイベント を無効にできます。 設定されているイベントの集
合や、同じイベントのほかのコード位置には影響しません。

コールバック関数から "sys.monitoring.DISABLE" を返すと、その他のイベン
ト をコードオブジェクト単位で無効にできます。 現在のツールについて、そ
のコードオブジェクト全体でイベントを無効にします。

特定の位置でイベントを無効にすることは、高性能なモニタリングのために非
常に重要です。 例えば、デバッガーがいくつかのブレークポイントを除くす
べてのモニタリングを無効にすれば、オーバーヘッドなしでデバッガーの下で
プログラムを実行できます。

sys.monitoring.restart_events() -> None

   すべてのツールについて、"sys.monitoring.DISABLE" で無効にしたイベン
   トをすべて有効にします。


コールバック関数の登録
======================

sys.monitoring.register_callback(tool_id: int, event: int, func: Callable | None, /) -> Callable | None

   指定した *tool_id* の *event* に対して、呼び出し可能オブジェクト
   *func* を登録します。

   指定した *tool_id* と *event* に別のコールバックが登録されていれば
   、その登録を解除して返します。 そうでなければ "register_callback()"
   は "None" を返します。

   引数 "func" を指定して 監査イベント
   "sys.monitoring.register_callback" を送出します。

"sys.monitoring.register_callback(tool_id, event, None)" を呼び出すと
、関数の登録を解除できます。

コールバック関数はいつでも登録・登録解除できます。

イベントがグローバルとローカルの両方で有効になっていても、コールバック
は 1 回だけ呼び出されます。 そのため、コードがイベントをグローバルとロ
ーカルの両方で有効にする可能性がある場合は、どちらによる呼び出しにも対
応できるようにコールバックを書く必要があります。


コールバック関数の引数
----------------------

sys.monitoring.MISSING

   呼び出しに引数がないことを示すため、コールバック関数に渡す特殊な値
   です。

有効なイベントが発生すると、登録されたコールバック関数を呼び出します。
コールバック関数が "DISABLE" 以外のオブジェクトを返しても、その戻り値
は何も影響しません。 イベントによってコールバック関数に渡す引数が次の
ように異なります:

* "PY_START" と "PY_RESUME"。

     func(code: CodeType, instruction_offset: int) -> object

* "PY_RETURN" と "PY_YIELD"。

     func(code: CodeType, instruction_offset: int, retval: object) -> object

* "CALL"、"C_RAISE"、"C_RETURN" (特に *arg0* は "MISSING" の場合があり
  ます)。

     func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object

  *code* は呼び出しが行われる場所のコードオブジェクトで、*callable* は
  呼び出す対象のオブジェクト (つまりイベントの発生元) です。 引数がな
  ければ、*arg0* は "sys.monitoring.MISSING" に設定されます。

  インスタンスメソッドの場合、*callable* はクラス上の関数オブジェクト
  で、*arg0* にはインスタンス (メソッドの "self" 引数) が設定されます
  。

* "RAISE"、"RERAISE"、"EXCEPTION_HANDLED"、"PY_UNWIND"、"PY_THROW"、
  "STOP_ITERATION"。

     func(code: CodeType, instruction_offset: int, exception: BaseException) -> object

* "LINE"。

     func(code: CodeType, line_number: int) -> object

* "BRANCH_LEFT"、"BRANCH_RIGHT"、"JUMP"。

     func(code: CodeType, instruction_offset: int, destination_offset: int) -> object

  *destination_offset* は、次にコードが実行される位置です。

* "INSTRUCTION"。

     func(code: CodeType, instruction_offset: int) -> object
