Skip to content

bpo-39491: Merge PEP 593 (typing.Annotated) support #18260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 101 additions & 1 deletion Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,7 @@ The module defines the following classes, functions and decorators:
runtime we intentionally don't check anything (we want this
to be as fast as possible).

.. function:: get_type_hints(obj[, globals[, locals]])
.. function:: get_type_hints(obj, globalns=None, localns=None, include_extras=False)

Return a dictionary containing type hints for a function, method, module
or class object.
Expand All @@ -1041,6 +1041,22 @@ The module defines the following classes, functions and decorators:
a dictionary constructed by merging all the ``__annotations__`` along
``C.__mro__`` in reverse order.

The function recursively replaces all ``Annotated[T, ...]`` with ``T``,
unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for
more information). For example::

class Student(NamedTuple):
name: Annotated[str, 'some marker']

get_type_hints(Student) == {'name': str}
get_type_hints(Student, include_extras=False) == {'name': str}
get_type_hints(Student, include_extras=True) == {
'name': Annotated[str, 'some marker']
}

.. versionchanged:: 3.9
Added ``include_extras`` parameter as part of :pep:`593`.

.. function:: get_origin(tp)
.. function:: get_args(tp)

Expand Down Expand Up @@ -1372,3 +1388,87 @@ The module defines the following classes, functions and decorators:
evaluated, so the second annotation does not need to be enclosed in quotes.

.. versionadded:: 3.5.2

.. data:: Annotated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I ask that you hint at the possibility of passing multiple extras (Annotated[T, x, y, z]) early in the description?


A type, introduced in :pep:`593` (``Flexible function and variable
annotations``), to decorate existing types with context-specific metadata
(possibly multiple pieces of it, as ``Annotated`` is variadic).
Specifically, a type ``T`` can be annotated with metadata ``x`` via the
typehint ``Annotated[T, x]``. This metadata can be used for either static
analysis or at runtime. If a library (or tool) encounters a typehint
``Annotated[T, x]`` and has no special logic for metadata ``x``, it
should ignore it and simply treat the type as ``T``. Unlike the
``no_type_check`` functionality that currently exists in the ``typing``
module which completely disables typechecking annotations on a function
or a class, the ``Annotated`` type allows for both static typechecking
of ``T`` (e.g., via mypy or Pyre, which can safely ignore ``x``)
together with runtime access to ``x`` within a specific application.

Ultimately, the responsibility of how to interpret the annotations (if
at all) is the responsibility of the tool or library encountering the
``Annotated`` type. A tool or library encountering an ``Annotated`` type
can scan through the annotations to determine if they are of interest
(e.g., using ``isinstance()``).

When a tool or a library does not support annotations or encounters an
unknown annotation it should just ignore it and treat annotated type as
the underlying type.

It's up to the tool consuming the annotations to decide whether the
client is allowed to have several annotations on one type and how to
merge those annotations.

Since the ``Annotated`` type allows you to put several annotations of
the same (or different) type(s) on any node, the tools or libraries
consuming those annotations are in charge of dealing with potential
duplicates. For example, if you are doing value range analysis you might
allow this::

T1 = Annotated[int, ValueRange(-10, 5)]
T2 = Annotated[T1, ValueRange(-20, 3)]

Passing ``include_extras=True`` to :func:`get_type_hints` lets one
access the extra annotations at runtime.

The details of the syntax:

* The first argument to ``Annotated`` must be a valid type

* Multiple type annotations are supported (``Annotated`` supports variadic
arguments)::

Annotated[int, ValueRange(3, 10), ctype("char")]

* ``Annotated`` must be called with at least two arguments (
``Annotated[int]`` is not valid)

* The order of the annotations is preserved and matters for equality
checks::

Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
int, ctype("char"), ValueRange(3, 10)
]

* Nested ``Annotated`` types are flattened, with metadata ordered
starting with the innermost annotation::

Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
int, ValueRange(3, 10), ctype("char")
]

* Duplicated annotations are not removed::

Annotated[int, ValueRange(3, 10)] != Annotated[
int, ValueRange(3, 10), ValueRange(3, 10)
]

* ``Annotated`` can be used with nested and generic aliases::

T = TypeVar('T')
Vec = Annotated[List[Tuple[T, T]], MaxLen(10)]
V = Vec[int]

V == Annotated[List[Tuple[int, int]], MaxLen(10)]

.. versionadded:: 3.9
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,14 @@ signal
Exposed the Linux-specific :func:`signal.pidfd_send_signal` for sending to
signals to a process using a file descriptor instead of a pid. (:issue:`38712`)

typing
------

:pep:`593` introduced an :data:`typing.Annotated` type to decorate existing
types with context-specific metadata and new ``include_extras`` parameter to
:func:`typing.get_type_hints` to access the metadata at runtime. (Contributed
by Till Varoquaux and Konstantin Kashin.)


Optimizations
=============
Expand Down
Loading