"annotationlib" --- アノテーションを調べるための機能
****************************************************

Added in version 3.14.

**ソースコード:** Lib/annotationlib.py

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

"annotationlib" モジュールは、モジュール、クラス、関数の *アノテーショ
ン* を調べるためのツールを提供します。

アノテーションは 遅延評価 され、作成時にはまだ定義されていないオブジェ
クトへの前方参照を含むことがよくあります。 このモジュールは、前方参照
やその他の特殊な場合があっても、アノテーションを確実に取得するための低
水準のツール群を提供します。

このモジュールは、アノテーションを取得するための三つの主要な形式をサポ
ートします ("Format" を参照)。 それぞれ適した用途が異なります。

* "VALUE" は、アノテーションを評価してその値を返します。 最も直接的に
  扱える形式ですが、未定義の名前を参照するアノテーションなどでは、エラ
  ーが発生する場合があります。

* "FORWARDREF" は、解決できないアノテーションに対して "ForwardRef" オ
  ブジェクトを返すので、それらを評価せずに調べられます。 未解決の前方
  参照を含む可能性のあるアノテーションを扱う場合に便利です。

* "STRING" は、ソースファイルでの表記に近い文字列としてアノテーション
  を返します。 アノテーションを読みやすく表示するドキュメント生成ツー
  ルなどに便利です。

アノテーションを取得する主な入口は "get_annotations()" 関数です。 関数
、クラス、モジュールを渡すと、指定した形式のアノテーション辞書を返しま
す。 このモジュールには、アノテーションの評価に使う *annotate 関数* を
直接扱う "get_annotate_from_class_namespace()" や
"call_annotate_function()"、および *evaluate 関数* を扱う
"call_evaluate_function()" もあります。

注意:

  このモジュールの大半の機能では、任意のコードが実行される可能性があり
  ます。 詳しくは セキュリティの節 を参照してください。

参考:

  現在の Python のアノテーションの動作モデルは **PEP 649** で提案され
  ました。

  **PEP 749** は **PEP 649** のさまざまな側面を詳しく規定し、
  "annotationlib" モジュールを導入しました。

  アノテーションを扱う際の推奨方法は アノテーションのベストプラクティ
  ス を参照してください。

  typing-extensions は、以前の Python バージョンでも使える
  "get_annotations()" のバックポートを提供します。


アノテーションの意味論
======================

Python 3 の歴史の中で、アノテーションの評価方法は変化してきました。 現
在も future インポート によって動作が変わります。 これまで、次の実行モ
デルが使われてきました。

* *従来の意味論* (Python 3.0 から 3.13 までのデフォルト。**PEP 3107**
  と **PEP 526** を参照): ソースコード内でアノテーションに到達した時点
  で、即座に評価します。

* *文字列化されたアノテーション* (Python 3.7 以降で "from __future__
  import annotations" を使った場合。**PEP 563** を参照): アノテーショ
  ンを文字列としてのみ保存します。

* *遅延評価* (Python 3.14 以降のデフォルト。**PEP 649** と **PEP 749**
  を参照): アノテーションにアクセスしたときに初めて評価します。

例として、次のプログラムを考えます。

   def func(a: Cls) -> None:
       print(a)

   class Cls: pass

   print(func.__annotations__)

動作は次のようになります。

* 従来の意味論 (Python 3.13 以前) では、"func" を定義する行で
  "NameError" が送出されます。 その時点では "Cls" が未定義だからです。

* 文字列化されたアノテーション ("from __future__ import annotations"
  を使った場合) では、"{'a': 'Cls', 'return': 'None'}" が表示されます
  。

* 遅延評価 (Python 3.14 以降) では、"{'a': <class 'Cls'>, 'return':
  None}" が表示されます。

Python 3.0 で関数のアノテーションが初めて導入されたとき (**PEP 3107**)
、実装方法として最も単純で分かりやすかったため、従来の意味論が採用され
ました。 Python 3.6 で変数のアノテーションが導入されたとき (**PEP
526**) も、同じ実行モデルが使われました。 しかし、アノテーションを型ヒ
ントとして使うと、アノテーションに到達した時点ではまだ定義されていない
名前を参照したい場合などに、問題が生じました。 また、モジュールのイン
ポート時にアノテーションを評価することには、性能上の問題もありました。
そのため、Python 3.7 では **PEP 563** により、"from __future__ import
annotations" という構文でアノテーションを文字列として保存する機能が導
入されました。 当初は将来この動作をデフォルトにする予定でしたが、実行
時にアノテーションを調べる用途では、文字列化されたアノテーションを処理
しにくいという問題が現れました。 代案の **PEP 649** は、三つ目の実行モ
デルである遅延評価を導入し、Python 3.14 に実装されました。 "from
__future__ import annotations" がある場合は今も文字列化されたアノテー
ションが使われますが、この動作はいずれ削除される予定です。


クラス
======

class annotationlib.Format

   アノテーションを返す形式を表す "IntEnum" です。 列挙型のメンバーま
   たは対応する整数値を、"get_annotations()" などのこのモジュールの関
   数や、"__annotate__" 関数に渡せます。

   VALUE = 1

      値は、アノテーションの式を評価した結果です。

   VALUE_WITH_FAKE_GLOBALS = 2

      annotate 関数が、仮のグローバル名前空間を持つ特別な環境で評価さ
      れていることを示す特別な値です。 この値を渡された annotate 関数
      は、"Format.VALUE" 形式と同じ値を返すか、この環境での実行をサポ
      ートしないことを示す "NotImplementedError" を送出する必要があり
      ます。 この形式は内部でのみ使われ、このモジュールの関数に渡すべ
      きではありません。

   FORWARDREF = 3

      定義済みの値には実際のアノテーションの値 ("Format.VALUE" 形式と
      同じ)、未定義の値には "ForwardRef" プロキシを使います。 実際のオ
      ブジェクトが "ForwardRef" プロキシオブジェクトへの参照を含むこと
      もあります。

   STRING = 4

      値は、ソースコード内のアノテーションの表記を文字列にしたものです
      。 ただし、空白の正規化や定数値の最適化などの変更が加わる場合が
      あり、変更はこれらに限りません。

      これらの文字列の厳密な値は、将来の Python バージョンで変わる可能
      性があります。

   Added in version 3.14.

class annotationlib.ForwardRef

   アノテーションの前方参照を表すプロキシオブジェクトです。

   "FORWARDREF" 形式を使い、アノテーションに解決できない名前が含まれて
   いる場合、このクラスのインスタンスが返されます。 例えば、定義前のク
   ラスを参照するなど、アノテーションが前方参照を含む場合に起こります
   。

   __forward_arg__

      "ForwardRef" を生成するために評価されたコードを含む文字列です。
      元のソースコードと完全には一致しない場合があります。

   evaluate(*, owner=None, globals=None, locals=None, type_params=None, format=Format.VALUE)

      前方参照を評価し、その値を返します。

      "format" 引数が "VALUE" (デフォルト) の場合、前方参照が解決でき
      ない名前を参照していると、"NameError" などの例外が送出されること
      があります。 このメソッドの引数を使うと、そうしなければ未定義と
      なる名前に値を束縛できます。 "format" 引数が "FORWARDREF" の場合
      、メソッドは例外を送出せず、"ForwardRef" インスタンスを返すこと
      があります。 例えば、前方参照オブジェクトが "list[undefined]" と
      いうコードを含み、"undefined" が未定義の名前である場合、
      "FORWARDREF" 形式で評価すると "list[ForwardRef('undefined')]" を
      返します。 "format" 引数が "STRING" の場合は、"__forward_arg__"
      を返します。

      このメソッドにスコープの情報を渡すには、"owner" パラメーターを使
      う方法を推奨します。 "ForwardRef" の所有者は、その "ForwardRef"
      の元となったアノテーションを含むオブジェクトです。 モジュールオ
      ブジェクト、型オブジェクト、関数オブジェクトなどが該当します。

      "globals"、"locals"、"type_params" パラメーターを使うと、
      "ForwardRef" の評価時に利用できる名前をより細かく制御できます。
      "globals" と "locals" は "eval()" に渡され、名前を評価するグロー
      バル名前空間とローカル名前空間を表します。 "type_params" は、ジ
      ェネリッククラス や ジェネリック関数 の専用構文で作成されたオブ
      ジェクトに関係します。 前方参照の評価時にスコープ内にある 型パラ
      メーター のタプルです。 例えば、ジェネリッククラス "C" のクラス
      名前空間にあるアノテーションから取得した "ForwardRef" を評価する
      場合、"type_params" に "C.__type_params__" を指定してください。

      "get_annotations()" が返す "ForwardRef" インスタンスは、元のスコ
      ープの情報への参照を保持します。 そのため、追加の引数を指定せず
      にこのメソッドを呼ぶだけで、評価できる場合があります。 他の方法
      で作った "ForwardRef" インスタンスにはスコープの情報がない場合が
      あるため、正しく評価するには引数を渡す必要があるかもしれません。

      "owner"、"globals"、"locals"、"type_params" をどれも指定せず、
      "ForwardRef" に元のスコープの情報がない場合、グローバルとローカ
      ルの名前空間には空の辞書を使います。

   Added in version 3.14.


関数
====

annotationlib.annotations_to_string(annotations)

   実行時の値を含むアノテーション辞書を、文字列だけを含む辞書に変換し
   ます。 値がまだ文字列でなければ、"type_repr()" で変換します。 これ
   は、"STRING" 形式をサポートするものの、アノテーションを作成したコー
   ドにはアクセスできない、ユーザー定義の annotate 関数を補助するため
   の関数です。

   例えば、関数形式の構文で作成した "typing.TypedDict" クラスの
   "STRING" 形式は、この関数で実装されています。

      >>> from typing import TypedDict
      >>> Movie = TypedDict("movie", {"name": str, "year": int})
      >>> get_annotations(Movie, format=Format.STRING)
      {'name': 'str', 'year': 'int'}

   Added in version 3.14.

annotationlib.call_annotate_function(annotate, format, *, owner=None)

   *annotate 関数* "annotate" を、"Format" 列挙型のメンバーである
   "format" を指定して呼び出し、その関数が生成したアノテーション辞書を
   返します。

   関数、クラス、モジュールのためにコンパイラが生成する annotate 関数
   は、直接呼び出した場合には "VALUE" 形式しかサポートしないため、この
   補助関数が必要です。 他の形式をサポートするため、この関数は特別な環
   境で annotate 関数を呼び出し、それらの形式のアノテーションを生成で
   きるようにします。 クラスの作成途中でアノテーションを部分的に評価す
   る機能を実装する際に役立ちます。

   "owner" はアノテーション関数を所有するオブジェクトで、通常は関数、
   クラス、モジュールのいずれかです。 指定すると、"FORWARDREF" 形式で
   、より多くの情報を持つ "ForwardRef" オブジェクトを生成するために使
   われます。

   参考: この関数で使われている実装手法は、**PEP 649** で説明されています
       。

   Added in version 3.14.

annotationlib.call_evaluate_function(evaluate, format, *, owner=None)

   *evaluate 関数* "evaluate" を、"Format" 列挙型のメンバーである
   "format" を指定して呼び出し、その関数が生成した値を返します。
   "call_annotate_function()" と似ていますが、そちらは常に文字列をアノ
   テーションに対応付ける辞書を返すのに対し、この関数は一つの値を返し
   ます。

   この関数は、型エイリアスや型パラメーターに関係する、遅延評価される
   要素のために生成された evaluate 関数で使うことを想定しています。

   * "typing.TypeAliasType.evaluate_value()": 型エイリアスの値

   * "typing.TypeVar.evaluate_bound()": 型変数の上限

   * "typing.TypeVar.evaluate_constraints()": 型変数の制約

   * "typing.TypeVar.evaluate_default()": 型変数のデフォルト値

   * "typing.ParamSpec.evaluate_default()": パラメーター仕様のデフォル
     ト値

   * "typing.TypeVarTuple.evaluate_default()": 型変数タプルのデフォル
     ト値

   "owner" は evaluate 関数を所有するオブジェクトです。 型エイリアスや
   型変数のオブジェクトなどが該当します。

   "format" で、値を返す形式を制御できます。

      >>> type Alias = undefined
      >>> call_evaluate_function(Alias.evaluate_value, Format.VALUE)
      Traceback (most recent call last):
      ...
      NameError: name 'undefined' is not defined
      >>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
      ForwardRef('undefined')
      >>> call_evaluate_function(Alias.evaluate_value, Format.STRING)
      'undefined'

   Added in version 3.14.

annotationlib.get_annotate_from_class_namespace(namespace)

   クラスの名前空間辞書 "namespace" から *annotate 関数* を取得します
   。 名前空間に annotate 関数がなければ "None" を返します。 主に、ク
   ラスの作成が完了する前 (メタクラス内など) に役立ちます。 クラスがで
   きた後は、"cls.__annotate__" で annotate 関数を取得できます。 メタ
   クラスでこの関数を使う例は 後述 します。

   Added in version 3.14.

annotationlib.get_annotations(obj, *, globals=None, locals=None, eval_str=False, format=Format.VALUE)

   オブジェクトに対するアノテーション辞書を計算します。

   "obj" には、呼び出し可能オブジェクト、クラス、モジュール、または
   "__annotate__" 属性か "__annotations__" 属性を持つ他のオブジェクト
   を指定できます。 それ以外のオブジェクトを渡すと "TypeError" が送出
   されます。

   "format" パラメーターはアノテーションを返す形式を制御し、"Format"
   列挙型のメンバーまたは対応する整数値を指定する必要があります。 各形
   式の動作は次のとおりです。

   * VALUE: まず "object.__annotations__" を試します。 それがなければ
     、"object.__annotate__" 関数があれば呼び出します。

   * FORWARDREF: "object.__annotations__" があり、正常に評価できればそ
     れを使います。 そうでなければ "object.__annotate__" 関数を呼び出
     します。 その関数もない場合は、再び "object.__annotations__" を試
     し、アクセス時のエラーを再送出します。

     * "object.__annotate__" は、まず "FORWARDREF" を指定して呼び出し
       ます。 その形式が実装されていなければ、
       "VALUE_WITH_FAKE_GLOBALS" のサポートを確認し、仮のグローバル名
       前空間を持つ環境で使います。 どちらの形式もサポートされていなけ
       れば、"VALUE" を使います。 "VALUE" での呼び出しが失敗した場合は
       、そのエラーを送出します。

   * STRING: "object.__annotate__" があれば、まずそれを呼び出します。
     なければ "object.__annotations__" を使い、
     "annotations_to_string()" で文字列化します。

     * "object.__annotate__" は、まず "STRING" を指定して呼び出します
       。 その形式が実装されていなければ、"VALUE_WITH_FAKE_GLOBALS" の
       サポートを確認し、仮のグローバル名前空間を持つ環境で使います。
       どちらの形式もサポートされていなければ、"VALUE" を使い、その結
       果を "annotations_to_string()" で変換します。 "VALUE" での呼び
       出しが失敗した場合は、そのエラーを送出します。

   辞書を返します。 "get_annotations()" は呼び出すたびに新しい辞書を返
   します。 同じオブジェクトに対して 2 回呼び出すと、内容は同じでも別
   々の辞書が返されます。

   この関数は、次の細部も処理します。

   * "eval_str" が真の場合、"str" 型の値を "eval()" で評価し、文字列化
     される前の値に戻します。 これは、文字列化されたアノテーション
     ("from __future__ import annotations") で使うことを想定しています
     。 "Format.VALUE" 以外の形式で "eval_str" を真にすると、エラーに
     なります。

   * "obj" にアノテーション辞書がなければ、空の辞書を返します。 (関数
     とメソッドには常にアノテーション辞書がありますが、クラス、モジュ
     ール、他の種類の呼び出し可能オブジェクトにはない場合があります。)

   * クラスが継承したアノテーションと、メタクラスのアノテーションは無
     視します。 クラス自体にアノテーション辞書がなければ、空の辞書を返
     します。

   * 安全のため、オブジェクトのメンバーと辞書の値へのアクセスには、す
     べて "getattr()" と "dict.get()" を使います。

   "eval_str" は、"str" 型の値を、その値に対して "eval()" を呼び出した
   結果に置き換えるかどうかを制御します。

   * "eval_str" が真の場合、"str" 型の値に対して "eval()" を呼び出しま
     す。 ("get_annotations()" は例外を捕捉しません。 "eval()" が例外
     を送出すると、"get_annotations()" の呼び出し元まで伝播します。)

   * "eval_str" が偽 (デフォルト) の場合、"str" 型の値は変更しません。

   "globals" と "locals" は "eval()" に渡されます。 詳しくは "eval()"
   のドキュメントを参照してください。 "globals" または "locals" が
   "None" の場合、この関数は "type(obj)" に応じて、その値を文脈に適し
   たデフォルト値に置き換えることがあります。

   * "obj" がモジュールの場合、"globals" のデフォルト値は
     "obj.__dict__" です。

   * "obj" がクラスの場合、"globals" のデフォルト値は
     "sys.modules[obj.__module__].__dict__"、"locals" のデフォルト値は
     "obj" のクラス名前空間です。

   * "obj" が呼び出し可能オブジェクトの場合、"globals" のデフォルト値
     は "obj.__globals__" です。 ただし、"obj" が
     ("functools.update_wrapper()" を使って) ラップされた関数か
     "functools.partial" オブジェクトの場合は、ラップされていない関数
     が見つかるまでラッパーをたどって外します。

   オブジェクトのアノテーション辞書へのアクセスには、
   "get_annotations()" の呼び出しを推奨します。 アノテーションの推奨さ
   れる扱い方については、アノテーションのベストプラクティス を参照して
   ください。

      >>> def f(a: int, b: str) -> float:
      ...     pass
      >>> get_annotations(f)
      {'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}

   Added in version 3.14.

annotationlib.type_repr(value)

   任意の Python の値を、"STRING" 形式での使用に適した表現に変換します
   。 大半のオブジェクトには "repr()" を呼び出しますが、型オブジェクト
   など一部のオブジェクトには特別な処理を行います。

   これは、"STRING" 形式をサポートするものの、アノテーションを作成した
   コードにはアクセスできない、ユーザー定義の annotate 関数を補助する
   ための関数です。 アノテーションでよく使われる値を含む他のオブジェク
   トについても、読みやすい文字列表現を提供するために使えます。

   Added in version 3.14.


レシピ
======


メタクラスでのアノテーションの利用
----------------------------------

メタクラス では、クラスの作成中にクラス本体のアノテーションを調べたり
変更したりしたい場合があります。 そのためには、クラスの名前空間辞書か
らアノテーションを取得する必要があります。 "from __future__ import
annotations" を使って作成されたクラスでは、アノテーションは辞書の
"__annotations__" キーにあります。 それ以外のアノテーションを持つクラ
スでは、"get_annotate_from_class_namespace()" で annotate 関数を取得し
、"call_annotate_function()" で呼び出してアノテーションを取得できます
。 クラスの作成時にはまだ解決できない名前をアノテーションで参照できる
よう、通常は "FORWARDREF" 形式を使うのが最適です。

アノテーションを変更するには、元の annotate 関数を呼び出して必要な調整
を加え、結果を返すラッパーの annotate 関数を作るのがよい方法です。

次の例は、クラスからすべての "typing.ClassVar" アノテーションを取り出
し、別の属性に格納するメタクラスです。

   import annotationlib
   import typing

   class ClassVarSeparator(type):
      def __new__(mcls, name, bases, ns):
         if "__annotations__" in ns:  # from __future__ import annotations
            annotations = ns["__annotations__"]
            classvar_keys = {
               key for key, value in annotations.items()
               # 簡単にするため文字列を比較する。より堅牢な方法には
               # annotationlib.ForwardRef.evaluate を使える
               if value.startswith("ClassVar")
            }
            classvars = {key: annotations[key] for key in classvar_keys}
            ns["__annotations__"] = {
               key: value for key, value in annotations.items()
               if key not in classvar_keys
            }
            wrapped_annotate = None
         elif annotate := annotationlib.get_annotate_from_class_namespace(ns):
            annotations = annotationlib.call_annotate_function(
               annotate, format=annotationlib.Format.FORWARDREF
            )
            classvar_keys = {
               key for key, value in annotations.items()
               if typing.get_origin(value) is typing.ClassVar
            }
            classvars = {key: annotations[key] for key in classvar_keys}

            def wrapped_annotate(format):
               annos = annotationlib.call_annotate_function(annotate, format, owner=typ)
               return {key: value for key, value in annos.items() if key not in classvar_keys}

         else:  # アノテーションなし
            classvars = {}
            wrapped_annotate = None
         typ = super().__new__(mcls, name, bases, ns)

         if wrapped_annotate is not None:
            # 元の __annotate__ を、ClassVar を取り除くラッパーで包む
            typ.__annotate__ = wrapped_annotate
         typ.classvars = classvars  # ClassVar を別の属性に格納する
         return typ


独自の呼び出し可能オブジェクトによる annotate 関数の作成
--------------------------------------------------------

独自の *annotate 関数* は、関数、クラス、モジュール用に自動生成される
ものと同じように、通常の関数で実装できます。 クラスによるカプセル化を
使いたい場合には、任意の *呼び出し可能オブジェクト* を *annotate 関数*
として使えます。

"VALUE"、"STRING"、"FORWARDREF" 形式を直接提供するには、*annotate 関数
* に次の属性が必要です。

* "__call__(format, /) -> dict" というシグネチャの呼び出し可能な
  "__call__"。 サポートする形式を指定して呼び出した場合に、
  "NotImplementedError" を送出しないもの。

"VALUE_WITH_FAKE_GLOBALS" 形式は、"STRING" や "FORWARDREF" が直接サポ
ートされていない場合に、それらを自動生成するために使われます。 この形
式を提供する *annotate 関数* には、次の属性が必要です。

* "__call__(format, /) -> dict" というシグネチャの呼び出し可能な
  "__call__"。 "VALUE_WITH_FAKE_GLOBALS" を指定して呼び出した場合に、
  "NotImplementedError" を送出しないもの。

* annotate 関数のコンパイル済みコードを含む コードオブジェクト
  "__code__"。

* 任意: "__code__" が表す関数が位置引数のデフォルト値を使う場合、その
  値のタプル "__defaults__"。

* 任意: "__code__" が表す関数がキーワード引数のデフォルト値を使う場合
  、その値の辞書 "__kwdefaults__"。

* 任意: その他すべての 関数の属性。

   class Annotate:
       called_formats = []

       def __call__(self, format=None, /, *, _self=None):
           # 仮のグローバル名前空間で呼ぶ場合、_self が実際の self の値、
           # self が形式になる。
           if _self is not None:
               self, format = _self, self

           self.called_formats.append(format)
           if format <= 2:  # VALUE または VALUE_WITH_FAKE_GLOBALS
               return {"x": MyType}
           raise NotImplementedError

       __code__ = __call__.__code__
       __defaults__ = (None,)
       __kwdefaults__ = property(lambda self: dict(_self=self))

       __globals__ = {}
       __builtins__ = {}
       __closure__ = None

次のように呼び出せます。

   >>> from annotationlib import call_annotate_function, Format
   >>> call_annotate_function(Annotate(), format=Format.STRING)
   {'x': 'MyType'}

また、オブジェクトの annotate 関数としても使えます。

   >>> from annotationlib import get_annotations, Format
   >>> class C:
   ...   pass
   >>> C.__annotate__ = Annotate()
   >>> get_annotations(Annotate(), format=Format.STRING)
   {'x': 'MyType'}


"STRING" 形式の制限
===================

"STRING" 形式は、アノテーションのソースコードに近い表現を生成するため
のものです。 ただし、使用している実装手法のため、元のソースコードを完
全に復元できるとは限りません。

第一に、文字列化の仕組みは、コンパイル済みコードに残っていない情報を復
元できません。 コメント、空白、括弧の付け方、コンパイラによって簡略化
された演算などが該当します。

第二に、文字列化の仕組みは、スコープから検索した名前を含む演算のほとん
どを横取りできますが、定数だけを対象にした演算は横取りできません。 そ
のため、信頼できないコードに対して "STRING" 形式を要求することも安全で
はありません。 Python は十分に強力なので、グローバル名や組み込み名に一
切アクセスしなくても、任意のコードを実行できます。 例を示します。

   >>> def f(x: (1).__class__.__base__.__subclasses__()[-1].__init__.__builtins__["print"]("Hello world")): pass
   ...
   >>> annotationlib.get_annotations(f, format=annotationlib.Format.STRING)
   Hello world
   {'x': 'None'}

注釈:

  この例は執筆時点では動作しますが、実装の詳細に依存しており、将来も動
  作する保証はありません。

"ast" モジュールで表される Python のさまざまな式のうち、一部はサポート
されており、"STRING" 形式で元のソースコードをおおむね復元できます。 そ
の他の式はサポートされておらず、誤った出力やエラーを生じる場合がありま
す。

次のものがサポートされています (一部には注意事項があります)。

* "ast.BinOp"

* "ast.UnaryOp"

  * "ast.Invert" ("~")、"ast.UAdd" ("+")、"ast.USub" ("-") はサポート
    されています。

  * "ast.Not" ("not") はサポートされていません。

* "ast.Dict" ("**" によるアンパックを使う場合を除く)

* "ast.Set"

* "ast.Compare"

  * "ast.Eq" と "ast.NotEq" はサポートされています。

  * "ast.Lt"、"ast.LtE"、"ast.Gt"、"ast.GtE" はサポートされていますが
    、オペランドが入れ替わる場合があります。

  * "ast.Is"、"ast.IsNot"、"ast.In"、"ast.NotIn" はサポートされていま
    せん。

* "ast.Call" ("**" によるアンパックを使う場合を除く)

* "ast.Constant" (ただし、定数の厳密な表記は保持されません。例えば、文
  字列内のエスケープシーケンスは失われ、16 進数は 10 進数に変換されま
  す)

* "ast.Attribute" (対象の値が定数ではない場合)

* "ast.Subscript" (対象の値が定数ではない場合)

* "ast.Starred" ("*" によるアンパック)

* "ast.Name"

* "ast.List"

* "ast.Tuple"

* "ast.Slice"

次のものはサポートされていませんが、文字列化の処理で検出すると、説明の
あるエラーを送出します。

* "ast.FormattedValue" (f 文字列。ただし、"!r" などの変換指定子がある
  場合はエラーを検出できません)

* "ast.JoinedStr" (f 文字列)

次のものはサポートされておらず、誤った出力になります。

* "ast.BoolOp" ("and" と "or")

* "ast.IfExp"

* "ast.Lambda"

* "ast.ListComp"

* "ast.SetComp"

* "ast.DictComp"

* "ast.GeneratorExp"

次のものはアノテーションスコープで禁止されているため、対象になりません
。

* "ast.NamedExpr" (":=")

* "ast.Await"

* "ast.Yield"

* "ast.YieldFrom"


"FORWARDREF" 形式の制限
=======================

"FORWARDREF" 形式は、可能な限り実際の値を生成し、解決できないものを
"ForwardRef" オブジェクトに置き換えようとします。 制限はおおむね
"STRING" 形式と同じです。 リテラルに対する演算や、サポートされていない
種類の式を含むアノテーションを "FORWARDREF" 形式で評価すると、例外が送
出される場合があります。

サポートされていない式での動作例をいくつか示します。

   >>> from annotationlib import get_annotations, Format
   >>> def zerodiv(x: 1 / 0): ...
   >>> get_annotations(zerodiv, format=Format.STRING)
   Traceback (most recent call last):
     ...
   ZeroDivisionError: division by zero
   >>> get_annotations(zerodiv, format=Format.FORWARDREF)
   Traceback (most recent call last):
     ...
   ZeroDivisionError: division by zero
   >>> def ifexp(x: 1 if y else 0): ...
   >>> get_annotations(ifexp, format=Format.STRING)
   {'x': '1'}


アノテーションを調べる際のセキュリティへの影響
==============================================

このモジュールの多くの機能はアノテーションに関係するコードを実行し、そ
のコードは任意の操作を行えます。 例えば、"get_annotations()" は任意の
*annotate 関数* を呼び出す可能性があり、"ForwardRef.evaluate()" は任意
の文字列に対して "eval()" を呼び出す可能性があります。 アノテーション
内のコードは、任意のシステムコールを実行したり、無限ループに入ったり、
その他のあらゆる操作を行ったりするかもしれません。 この点は、
"__annotations__" 属性へのあらゆるアクセスや、
"typing.get_type_hints()" など、アノテーションを扱う "typing" モジュー
ルの関数にも当てはまります。

このことから生じるセキュリティの問題は、信頼できないアノテーションを含
む可能性があるコードをインポートした直後にも当てはまります。 コードの
インポートでは、常に任意の操作が実行され得るためです。 ただし、信頼で
きない入力元から文字列などを受け取り、アノテーションを調べる API に渡
すのは安全ではありません。 例えば、"__annotations__" 辞書の編集や、
"ForwardRef" オブジェクトの直接作成によって、そのような入力を渡す場合
が該当します。
