Skip to content

Commit cf5b109

Browse files
authored
bpo-39491: Merge PEP 593 (typing.Annotated) support (#18260)
* bpo-39491: Merge PEP 593 (typing.Annotated) support PEP 593 has been accepted some time ago. I got a green light for merging this from Till, so I went ahead and combined the code contributed to typing_extensions[1] and the documentation from the PEP 593 text[2]. My changes were limited to: * removing code designed for typing_extensions to run on older Python versions * removing some irrelevant parts of the PEP text when copying it over as documentation and otherwise changing few small bits to better serve the purpose * changing the get_type_hints signature to match reality (parameter names) I wasn't entirely sure how to go about crediting the authors but I used my best judgment, let me know if something needs changing in this regard. [1] https://github.com/python/typing/blob/8280de241fd8c8afe727c7860254b753e383b360/typing_extensions/src_py3/typing_extensions.py [2] https://github.com/python/peps/blob/17710b879882454d55f82c2d44596e8e9f8e4bff/pep-0593.rst
1 parent 89ae20b commit cf5b109

File tree

5 files changed

+467
-6
lines changed

5 files changed

+467
-6
lines changed

Doc/library/typing.rst

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ The module defines the following classes, functions and decorators:
10281028
runtime we intentionally don't check anything (we want this
10291029
to be as fast as possible).
10301030

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

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

1044+
The function recursively replaces all ``Annotated[T, ...]`` with ``T``,
1045+
unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for
1046+
more information). For example::
1047+
1048+
class Student(NamedTuple):
1049+
name: Annotated[str, 'some marker']
1050+
1051+
get_type_hints(Student) == {'name': str}
1052+
get_type_hints(Student, include_extras=False) == {'name': str}
1053+
get_type_hints(Student, include_extras=True) == {
1054+
'name': Annotated[str, 'some marker']
1055+
}
1056+
1057+
.. versionchanged:: 3.9
1058+
Added ``include_extras`` parameter as part of :pep:`593`.
1059+
10441060
.. function:: get_origin(tp)
10451061
.. function:: get_args(tp)
10461062

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

13741390
.. versionadded:: 3.5.2
1391+
1392+
.. data:: Annotated
1393+
1394+
A type, introduced in :pep:`593` (``Flexible function and variable
1395+
annotations``), to decorate existing types with context-specific metadata
1396+
(possibly multiple pieces of it, as ``Annotated`` is variadic).
1397+
Specifically, a type ``T`` can be annotated with metadata ``x`` via the
1398+
typehint ``Annotated[T, x]``. This metadata can be used for either static
1399+
analysis or at runtime. If a library (or tool) encounters a typehint
1400+
``Annotated[T, x]`` and has no special logic for metadata ``x``, it
1401+
should ignore it and simply treat the type as ``T``. Unlike the
1402+
``no_type_check`` functionality that currently exists in the ``typing``
1403+
module which completely disables typechecking annotations on a function
1404+
or a class, the ``Annotated`` type allows for both static typechecking
1405+
of ``T`` (e.g., via mypy or Pyre, which can safely ignore ``x``)
1406+
together with runtime access to ``x`` within a specific application.
1407+
1408+
Ultimately, the responsibility of how to interpret the annotations (if
1409+
at all) is the responsibility of the tool or library encountering the
1410+
``Annotated`` type. A tool or library encountering an ``Annotated`` type
1411+
can scan through the annotations to determine if they are of interest
1412+
(e.g., using ``isinstance()``).
1413+
1414+
When a tool or a library does not support annotations or encounters an
1415+
unknown annotation it should just ignore it and treat annotated type as
1416+
the underlying type.
1417+
1418+
It's up to the tool consuming the annotations to decide whether the
1419+
client is allowed to have several annotations on one type and how to
1420+
merge those annotations.
1421+
1422+
Since the ``Annotated`` type allows you to put several annotations of
1423+
the same (or different) type(s) on any node, the tools or libraries
1424+
consuming those annotations are in charge of dealing with potential
1425+
duplicates. For example, if you are doing value range analysis you might
1426+
allow this::
1427+
1428+
T1 = Annotated[int, ValueRange(-10, 5)]
1429+
T2 = Annotated[T1, ValueRange(-20, 3)]
1430+
1431+
Passing ``include_extras=True`` to :func:`get_type_hints` lets one
1432+
access the extra annotations at runtime.
1433+
1434+
The details of the syntax:
1435+
1436+
* The first argument to ``Annotated`` must be a valid type
1437+
1438+
* Multiple type annotations are supported (``Annotated`` supports variadic
1439+
arguments)::
1440+
1441+
Annotated[int, ValueRange(3, 10), ctype("char")]
1442+
1443+
* ``Annotated`` must be called with at least two arguments (
1444+
``Annotated[int]`` is not valid)
1445+
1446+
* The order of the annotations is preserved and matters for equality
1447+
checks::
1448+
1449+
Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
1450+
int, ctype("char"), ValueRange(3, 10)
1451+
]
1452+
1453+
* Nested ``Annotated`` types are flattened, with metadata ordered
1454+
starting with the innermost annotation::
1455+
1456+
Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
1457+
int, ValueRange(3, 10), ctype("char")
1458+
]
1459+
1460+
* Duplicated annotations are not removed::
1461+
1462+
Annotated[int, ValueRange(3, 10)] != Annotated[
1463+
int, ValueRange(3, 10), ValueRange(3, 10)
1464+
]
1465+
1466+
* ``Annotated`` can be used with nested and generic aliases::
1467+
1468+
T = TypeVar('T')
1469+
Vec = Annotated[List[Tuple[T, T]], MaxLen(10)]
1470+
V = Vec[int]
1471+
1472+
V == Annotated[List[Tuple[int, int]], MaxLen(10)]
1473+
1474+
.. versionadded:: 3.9

Doc/whatsnew/3.9.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,14 @@ signal
303303
Exposed the Linux-specific :func:`signal.pidfd_send_signal` for sending to
304304
signals to a process using a file descriptor instead of a pid. (:issue:`38712`)
305305

306+
typing
307+
------
308+
309+
:pep:`593` introduced an :data:`typing.Annotated` type to decorate existing
310+
types with context-specific metadata and new ``include_extras`` parameter to
311+
:func:`typing.get_type_hints` to access the metadata at runtime. (Contributed
312+
by Till Varoquaux and Konstantin Kashin.)
313+
306314

307315
Optimizations
308316
=============

0 commit comments

Comments
 (0)