2024-09-11 11:49:59 -03:00
|
|
|
:mod:`!annotationlib` --- Functionality for introspecting annotations
|
|
|
|
=====================================================================
|
|
|
|
|
|
|
|
.. module:: annotationlib
|
|
|
|
:synopsis: Functionality for introspecting annotations
|
|
|
|
|
|
|
|
|
|
|
|
**Source code:** :source:`Lib/annotationlib.py`
|
|
|
|
|
|
|
|
.. testsetup:: default
|
|
|
|
|
|
|
|
import annotationlib
|
|
|
|
from annotationlib import *
|
|
|
|
|
|
|
|
--------------
|
|
|
|
|
|
|
|
The :mod:`!annotationlib` module provides tools for introspecting
|
|
|
|
:term:`annotations <annotation>` on modules, classes, and functions.
|
|
|
|
|
|
|
|
Annotations are :ref:`lazily evaluated <lazy-evaluation>` and often contain
|
|
|
|
forward references to objects that are not yet defined when the annotation
|
|
|
|
is created. This module provides a set of low-level tools that can be used to retrieve annotations in a reliable way, even
|
|
|
|
in the presence of forward references and other edge cases.
|
|
|
|
|
|
|
|
This module supports retrieving annotations in three main formats
|
|
|
|
(see :class:`Format`), each of which works best for different use cases:
|
|
|
|
|
|
|
|
* :attr:`~Format.VALUE` evaluates the annotations and returns their value.
|
|
|
|
This is most straightforward to work with, but it may raise errors,
|
|
|
|
for example if the annotations contain references to undefined names.
|
|
|
|
* :attr:`~Format.FORWARDREF` returns :class:`ForwardRef` objects
|
|
|
|
for annotations that cannot be resolved, allowing you to inspect the
|
|
|
|
annotations without evaluating them. This is useful when you need to
|
|
|
|
work with annotations that may contain unresolved forward references.
|
|
|
|
* :attr:`~Format.SOURCE` returns the annotations as a string, similar
|
|
|
|
to how it would appear in the source file. This is useful for documentation
|
|
|
|
generators that want to display annotations in a readable way.
|
|
|
|
|
|
|
|
The :func:`get_annotations` function is the main entry point for
|
|
|
|
retrieving annotations. Given a function, class, or module, it returns
|
|
|
|
an annotations dictionary in the requested format. This module also provides
|
|
|
|
functionality for working directly with the :term:`annotate function`
|
|
|
|
that is used to evaluate annotations, such as :func:`get_annotate_function`
|
|
|
|
and :func:`call_annotate_function`, as well as the
|
|
|
|
:func:`call_evaluate_function` function for working with
|
|
|
|
:term:`evaluate functions <evaluate function>`.
|
|
|
|
|
|
|
|
|
|
|
|
.. seealso::
|
|
|
|
|
|
|
|
:pep:`649` proposed the current model for how annotations work in Python.
|
|
|
|
|
|
|
|
:pep:`749` expanded on various aspects of :pep:`649` and introduced the
|
|
|
|
:mod:`!annotationlib` module.
|
|
|
|
|
|
|
|
:ref:`annotations-howto` provides best practices for working with
|
|
|
|
annotations.
|
|
|
|
|
|
|
|
:pypi:`typing-extensions` provides a backport of :func:`get_annotations`
|
|
|
|
that works on earlier versions of Python.
|
|
|
|
|
|
|
|
Annotation semantics
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
The way annotations are evaluated has changed over the history of Python 3,
|
|
|
|
and currently still depends on a :ref:`future import <future>`.
|
|
|
|
There have been execution models for annotations:
|
|
|
|
|
|
|
|
* *Stock semantics* (default in Python 3.0 through 3.13; see :pep:`3107`
|
|
|
|
and :pep:`526`): Annotations are evaluated eagerly, as they are
|
|
|
|
encountered in the source code.
|
|
|
|
* *Stringified annotations* (used with ``from __future__ import annotations``
|
|
|
|
in Python 3.7 and newer; see :pep:`563`): Annotations are stored as
|
|
|
|
strings only.
|
|
|
|
* *Deferred evaluation* (default in Python 3.14 and newer; see :pep:`649` and
|
|
|
|
:pep:`749`): Annotations are evaluated lazily, only when they are accessed.
|
|
|
|
|
|
|
|
As an example, consider the following program::
|
|
|
|
|
|
|
|
def func(a: Cls) -> None:
|
|
|
|
print(a)
|
|
|
|
|
|
|
|
class Cls: pass
|
|
|
|
|
|
|
|
print(func.__annotations__)
|
|
|
|
|
|
|
|
This will behave as follows:
|
|
|
|
|
|
|
|
* Under stock semantics (Python 3.13 and earlier), it will throw a
|
|
|
|
:exc:`NameError` at the line where ``func`` is defined,
|
|
|
|
because ``Cls`` is an undefined name at that point.
|
|
|
|
* Under stringified annotations (if ``from __future__ import annotations``
|
|
|
|
is used), it will print ``{'a': 'Cls', 'return': 'None'}``.
|
|
|
|
* Under deferred evaluation (Python 3.14 and later), it will print
|
|
|
|
``{'a': <class 'Cls'>, 'return': None}``.
|
|
|
|
|
|
|
|
Stock semantics were used when function annotations were first introduced
|
|
|
|
in Python 3.0 (by :pep:`3107`) because this was the simplest, most obvious
|
|
|
|
way to implement annotations. The same execution model was used when variable
|
|
|
|
annotations were introduced in Python 3.6 (by :pep:`526`). However,
|
|
|
|
stock semantics caused problems when using annotations as type hints,
|
|
|
|
such as a need to refer to names that are not yet defined when the
|
|
|
|
annotation is encountered. In addition, there were performance problems
|
|
|
|
with executing annotations at module import time. Therefore, in Python 3.7,
|
|
|
|
:pep:`563` introduced the ability to store annotations as strings using the
|
|
|
|
``from __future__ import annotations`` syntax. The plan at the time was to
|
|
|
|
eventually make this behavior the default, but a problem appeared:
|
|
|
|
stringified annotations are more difficult to process for those who
|
|
|
|
introspect annotations at runtime. An alternative proposal, :pep:`649`,
|
|
|
|
introduced the third execution model, deferred evaluation, and was implemented
|
|
|
|
in Python 3.14. Stringified annotations are still used if
|
|
|
|
``from __future__ import annotations`` is present, but this behavior will
|
|
|
|
eventually be removed.
|
|
|
|
|
|
|
|
Classes
|
|
|
|
-------
|
|
|
|
|
|
|
|
.. class:: Format
|
|
|
|
|
|
|
|
An :class:`~enum.IntEnum` describing the formats in which annotations
|
|
|
|
can be returned. Members of the enum, or their equivalent integer values,
|
|
|
|
can be passed to :func:`get_annotations` and other functions in this
|
|
|
|
module, as well as to :attr:`~object.__annotate__` functions.
|
|
|
|
|
|
|
|
.. attribute:: VALUE
|
|
|
|
:value: 1
|
|
|
|
|
|
|
|
Values are the result of evaluating the annotation expressions.
|
|
|
|
|
|
|
|
.. attribute:: FORWARDREF
|
|
|
|
:value: 2
|
|
|
|
|
|
|
|
Values are real annotation values (as per :attr:`Format.VALUE` format)
|
|
|
|
for defined values, and :class:`ForwardRef` proxies for undefined
|
|
|
|
values. Real objects may contain references to, :class:`ForwardRef`
|
|
|
|
proxy objects.
|
|
|
|
|
|
|
|
.. attribute:: SOURCE
|
|
|
|
:value: 3
|
|
|
|
|
|
|
|
Values are the text string of the annotation as it appears in the
|
|
|
|
source code, up to modifications including, but not restricted to,
|
|
|
|
whitespace normalizations and constant values optimizations.
|
|
|
|
|
|
|
|
The exact values of these strings may change in future versions of Python.
|
|
|
|
|
|
|
|
.. versionadded:: 3.14
|
|
|
|
|
|
|
|
.. class:: ForwardRef
|
|
|
|
|
|
|
|
A proxy object for forward references in annotations.
|
|
|
|
|
|
|
|
Instances of this class are returned when the :attr:`~Format.FORWARDREF`
|
|
|
|
format is used and annotations contain a name that cannot be resolved.
|
|
|
|
This can happen when a forward reference is used in an annotation, such as
|
|
|
|
when a class is referenced before it is defined.
|
|
|
|
|
|
|
|
.. attribute:: __forward_arg__
|
|
|
|
|
|
|
|
A string containing the code that was evaluated to produce the
|
|
|
|
:class:`~ForwardRef`. The string may not be exactly equivalent
|
|
|
|
to the original source.
|
|
|
|
|
|
|
|
.. method:: evaluate(*, globals=None, locals=None, type_params=None, owner=None)
|
|
|
|
|
|
|
|
Evaluate the forward reference, returning its value.
|
|
|
|
|
|
|
|
This may throw an exception, such as :exc:`NameError`, if the forward
|
|
|
|
reference refers to names that do not exist. The arguments to this
|
|
|
|
method can be used to provide bindings for names that would otherwise
|
|
|
|
be undefined.
|
|
|
|
|
|
|
|
:class:`~ForwardRef` instances returned by :func:`get_annotations`
|
|
|
|
retain references to information about the scope they originated from,
|
|
|
|
so calling this method with no further arguments may be sufficient to
|
|
|
|
evaluate such objects. :class:`~ForwardRef` instances created by other
|
|
|
|
means may not have any information about their scope, so passing
|
|
|
|
arguments to this method may be necessary to evaluate them successfully.
|
|
|
|
|
|
|
|
*globals* and *locals* are passed to :func:`eval`, representing
|
|
|
|
the global and local namespaces in which the name is evaluated.
|
|
|
|
*type_params*, if given, must be a tuple of
|
|
|
|
:ref:`type parameters <type-params>` that are in scope while the forward
|
|
|
|
reference is being evaluated. *owner* is the object that owns the
|
|
|
|
annotation from which the forward reference derives, usually a function,
|
|
|
|
class, or module.
|
|
|
|
|
|
|
|
.. important::
|
|
|
|
|
|
|
|
Once a :class:`~ForwardRef` instance has been evaluated, it caches
|
|
|
|
the evaluated value, and future calls to :meth:`evaluate` will return
|
|
|
|
the cached value, regardless of the parameters passed in.
|
|
|
|
|
|
|
|
.. versionadded:: 3.14
|
|
|
|
|
|
|
|
|
|
|
|
Functions
|
|
|
|
---------
|
|
|
|
|
|
|
|
.. function:: call_annotate_function(annotate, format, *, owner=None)
|
|
|
|
|
|
|
|
Call the :term:`annotate function` *annotate* with the given *format*,
|
|
|
|
a member of the :class:`Format` enum, and return the annotations
|
|
|
|
dictionary produced by the function.
|
|
|
|
|
|
|
|
This helper function is required because annotate functions generated by
|
|
|
|
the compiler for functions, classes, and modules only support
|
|
|
|
the :attr:`~Format.VALUE` format when called directly.
|
|
|
|
To support other formats, this function calls the annotate function
|
|
|
|
in a special environment that allows it to produce annotations in the
|
|
|
|
other formats. This is a useful building block when implementing
|
|
|
|
functionality that needs to partially evaluate annotations while a class
|
|
|
|
is being constructed.
|
|
|
|
|
|
|
|
*owner* is the object that owns the annotation function, usually
|
|
|
|
a function, class, or module. If provided, it is used in the
|
|
|
|
:attr:`~Format.FORWARDREF` format to produce a :class:`ForwardRef`
|
|
|
|
object that carries more information.
|
|
|
|
|
|
|
|
.. seealso::
|
|
|
|
|
|
|
|
:PEP:`PEP 649 <649#the-stringizer-and-the-fake-globals-environment>`
|
|
|
|
contains an explanation of the implementation technique used by this
|
|
|
|
function.
|
|
|
|
|
|
|
|
.. versionadded:: 3.14
|
|
|
|
|
|
|
|
.. function:: call_evaluate_function(evaluate, format, *, owner=None)
|
|
|
|
|
|
|
|
Call the :term:`evaluate function` *evaluate* with the given *format*,
|
|
|
|
a member of the :class:`Format` enum, and return the value produced by
|
|
|
|
the function. This is similar to :func:`call_annotate_function`,
|
|
|
|
but the latter always returns a dictionary mapping strings to annotations,
|
|
|
|
while this function returns a single value.
|
|
|
|
|
|
|
|
This is intended for use with the evaluate functions generated for lazily
|
|
|
|
evaluated elements related to type aliases and type parameters:
|
|
|
|
|
|
|
|
* :meth:`typing.TypeAliasType.evaluate_value`, the value of type aliases
|
|
|
|
* :meth:`typing.TypeVar.evaluate_bound`, the bound of type variables
|
|
|
|
* :meth:`typing.TypeVar.evaluate_constraints`, the constraints of
|
|
|
|
type variables
|
|
|
|
* :meth:`typing.TypeVar.evaluate_default`, the default value of
|
|
|
|
type variables
|
|
|
|
* :meth:`typing.ParamSpec.evaluate_default`, the default value of
|
|
|
|
parameter specifications
|
|
|
|
* :meth:`typing.TypeVarTuple.evaluate_default`, the default value of
|
|
|
|
type variable tuples
|
|
|
|
|
|
|
|
*owner* is the object that owns the evaluate function, such as the type
|
|
|
|
alias or type variable object.
|
|
|
|
|
|
|
|
*format* can be used to control the format in which the value is returned:
|
|
|
|
|
|
|
|
.. doctest::
|
|
|
|
|
|
|
|
>>> 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.SOURCE)
|
|
|
|
'undefined'
|
|
|
|
|
|
|
|
.. versionadded:: 3.14
|
|
|
|
|
|
|
|
.. function:: get_annotate_function(obj)
|
|
|
|
|
|
|
|
Retrieve the :term:`annotate function` for *obj*. Return :const:`!None`
|
|
|
|
if *obj* does not have an annotate function.
|
|
|
|
|
|
|
|
This is usually equivalent to accessing the :attr:`~object.__annotate__`
|
|
|
|
attribute of *obj*, but direct access to the attribute may return the wrong
|
|
|
|
object in certain situations involving metaclasses. This function should be
|
|
|
|
used instead of accessing the attribute directly.
|
|
|
|
|
|
|
|
.. versionadded:: 3.14
|
|
|
|
|
|
|
|
.. function:: get_annotations(obj, *, globals=None, locals=None, eval_str=False, format=Format.VALUE)
|
|
|
|
|
|
|
|
Compute the annotations dict for an object.
|
|
|
|
|
|
|
|
*obj* may be a callable, class, module, or other object with
|
|
|
|
:attr:`~object.__annotate__` and :attr:`~object.__annotations__` attributes.
|
|
|
|
Passing in an object of any other type raises :exc:`TypeError`.
|
|
|
|
|
|
|
|
The *format* parameter controls the format in which annotations are returned,
|
|
|
|
and must be a member of the :class:`Format` enum or its integer equivalent.
|
|
|
|
|
|
|
|
Returns a dict. :func:`!get_annotations` returns a new dict every time
|
|
|
|
it's called; calling it twice on the same object will return two
|
|
|
|
different but equivalent dicts.
|
|
|
|
|
|
|
|
This function handles several details for you:
|
|
|
|
|
|
|
|
* If *eval_str* is true, values of type :class:`!str` will
|
|
|
|
be un-stringized using :func:`eval`. This is intended
|
|
|
|
for use with stringized annotations
|
|
|
|
(``from __future__ import annotations``). It is an error
|
|
|
|
to set *eval_str* to true with formats other than :attr:`Format.VALUE`.
|
|
|
|
* If *obj* doesn't have an annotations dict, returns an
|
|
|
|
empty dict. (Functions and methods always have an
|
|
|
|
annotations dict; classes, modules, and other types of
|
|
|
|
callables may not.)
|
|
|
|
* Ignores inherited annotations on classes, as well as annotations
|
|
|
|
on metaclasses. If a class
|
|
|
|
doesn't have its own annotations dict, returns an empty dict.
|
|
|
|
* All accesses to object members and dict values are done
|
|
|
|
using ``getattr()`` and ``dict.get()`` for safety.
|
|
|
|
|
|
|
|
*eval_str* controls whether or not values of type :class:`!str` are
|
|
|
|
replaced with the result of calling :func:`eval` on those values:
|
|
|
|
|
|
|
|
* If eval_str is true, :func:`eval` is called on values of type
|
|
|
|
:class:`!str`. (Note that :func:`!get_annotations` doesn't catch
|
2024-09-11 15:05:15 -03:00
|
|
|
exceptions; if :func:`eval` raises an exception, it will unwind
|
2024-09-11 11:49:59 -03:00
|
|
|
the stack past the :func:`!get_annotations` call.)
|
|
|
|
* If *eval_str* is false (the default), values of type :class:`!str` are
|
|
|
|
unchanged.
|
|
|
|
|
|
|
|
*globals* and *locals* are passed in to :func:`eval`; see the documentation
|
|
|
|
for :func:`eval` for more information. If *globals* or *locals*
|
|
|
|
is :const:`!None`, this function may replace that value with a
|
|
|
|
context-specific default, contingent on ``type(obj)``:
|
|
|
|
|
|
|
|
* If *obj* is a module, *globals* defaults to ``obj.__dict__``.
|
|
|
|
* If *obj* is a class, *globals* defaults to
|
|
|
|
``sys.modules[obj.__module__].__dict__`` and *locals* defaults
|
|
|
|
to the *obj* class namespace.
|
|
|
|
* If *obj* is a callable, *globals* defaults to
|
|
|
|
:attr:`obj.__globals__ <function.__globals__>`,
|
|
|
|
although if *obj* is a wrapped function (using
|
|
|
|
:func:`functools.update_wrapper`) or a :class:`functools.partial` object,
|
|
|
|
it is unwrapped until a non-wrapped function is found.
|
|
|
|
|
|
|
|
Calling :func:`!get_annotations` is best practice for accessing the
|
|
|
|
annotations dict of any object. See :ref:`annotations-howto` for
|
|
|
|
more information on annotations best practices.
|
|
|
|
|
|
|
|
.. doctest::
|
|
|
|
|
|
|
|
>>> def f(a: int, b: str) -> float:
|
|
|
|
... pass
|
|
|
|
>>> get_annotations(f)
|
|
|
|
{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}
|
|
|
|
|
|
|
|
.. versionadded:: 3.14
|