From 6eba81f8c6985f78ff2cd8581990922f090f7c22 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 6 Jun 2023 12:05:23 +0100 Subject: [PATCH 1/2] gh-97797: Improve documentation for typing.Annotated --- Doc/library/typing.rst | 79 ++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a9ea4b9fee3ad4..dd54bf4c5fd2b6 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2,6 +2,12 @@ :mod:`typing` --- Support for type hints ======================================== +.. testsetup:: * + + import typing + from dataclasses import dataclass + from typing import * + .. module:: typing :synopsis: Support for type hints (see :pep:`484`). @@ -1135,7 +1141,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn (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 + analysis or at runtime: at runtime, it is stored in a :attr:`__metadata__` + attribute. 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`` @@ -1162,10 +1169,17 @@ These can be used as types in annotations using ``[]``, each having a unique syn 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:: + allow this: + + .. testcode:: + + @dataclass + class ValueRange: + lo: int + hi: int - T1 = Annotated[int, ValueRange(-10, 5)] - T2 = Annotated[T1, ValueRange(-20, 3)] + 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. @@ -1177,7 +1191,11 @@ These can be used as types in annotations using ``[]``, each having a unique syn * Multiple type annotations are supported (``Annotated`` supports variadic arguments):: - Annotated[int, ValueRange(3, 10), ctype("char")] + @dataclass + class ctype: + kind: str + + Annotated[int, ValueRange(3, 10), ctype("char")] * ``Annotated`` must be called with at least two arguments ( ``Annotated[int]`` is not valid) @@ -1185,30 +1203,53 @@ These can be used as types in annotations using ``[]``, each having a unique syn * 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) - ] + assert 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") - ] + assert 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) - ] + assert Annotated[int, ValueRange(3, 10)] != Annotated[ + int, ValueRange(3, 10), ValueRange(3, 10) + ] + + * ``Annotated`` can be used with nested and generic aliases: + + .. testcode:: - * ``Annotated`` can be used with nested and generic aliases:: + T = TypeVar('T') - T = TypeVar('T') - Vec = Annotated[list[tuple[T, T]], MaxLen(10)] - V = Vec[int] + @dataclass + class MaxLen: + value: int + + Vec = Annotated[list[tuple[T, T]], MaxLen(10)] + V = Vec[int] + + assert V == Annotated[list[tuple[int, int]], MaxLen(10)] + + .. attribute:: __metadata__ + + At runtime, the metadata associated with an ``Annotated`` type can be + retrieved via the ``__metadata__`` attribute. + + For example: + + .. doctest:: - V == Annotated[list[tuple[int, int]], MaxLen(10)] + >>> from typing import Annotated + >>> X = Annotated[int, "very", "important", "metadata"] + >>> X + typing.Annotated[int, 'very', 'important', 'metadata'] + >>> X.__metadata__ + ('very', 'important', 'metadata') .. versionadded:: 3.9 From bae8f9484579d8d94c3514cbaa51a5309bcbf2f5 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Wed, 7 Jun 2023 09:15:56 +0100 Subject: [PATCH 2/2] Use PEP-695 syntax --- Doc/library/typing.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index e684259e79896f..1c3485e2008e55 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1246,16 +1246,15 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. testcode:: - T = TypeVar('T') - @dataclass class MaxLen: value: int - Vec = Annotated[list[tuple[T, T]], MaxLen(10)] - V = Vec[int] + type Vec[T] = Annotated[list[tuple[T, T]], MaxLen(10)] - assert V == Annotated[list[tuple[int, int]], MaxLen(10)] + # When used in a type annotation, a type checker will treat "V" the same as + # ``Annotated[list[tuple[int, int]], MaxLen(10)]``: + type V = Vec[int] .. attribute:: __metadata__