From 7dc0ee8649376b64388b471200f9bedaae726612 Mon Sep 17 00:00:00 2001 From: Valentin Berlier Date: Fri, 14 Feb 2025 18:03:11 +0100 Subject: [PATCH 1/6] Document that nested `Annotated` types referenced through a type alias are not flattened --- Doc/library/typing.rst | 8 ++++++++ Lib/typing.py | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 0fee782121b0af..989f04e9c16cac 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1402,6 +1402,14 @@ These can be used as types in annotations. They all support subscription using int, ValueRange(3, 10), ctype("char") ] + However, this does not apply to ``Annotated`` types referenced through a type + alias:: + + type From3To10[T] = Annotated[T, ValueRange(3, 10)] + assert Annotated[From3To10[int], ctype("char")] != Annotated[ + int, ValueRange(3, 10), ctype("char") + ] + * Duplicated metadata elements are not removed:: assert Annotated[int, ValueRange(3, 10)] != Annotated[ diff --git a/Lib/typing.py b/Lib/typing.py index 66570db7a5bd74..79b3e84c071171 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2239,6 +2239,12 @@ def Annotated(self, *params): assert Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + However, this does not apply to Annotated types referenced through + a type alias:: + + type A[T] = Annotated[T, Ann1, Ann2] + assert Annotated[A[T], Ann3] != Annotated[T, Ann1, Ann2, Ann3] + - Instantiating an annotated type is equivalent to instantiating the underlying type:: From 88fb637fd508bcc5718a6ef24fe608e36a224e07 Mon Sep 17 00:00:00 2001 From: Valentin Berlier Date: Fri, 14 Feb 2025 20:14:35 +0100 Subject: [PATCH 2/6] Explain why alias is not flattened --- Doc/library/typing.rst | 2 +- Lib/typing.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 989f04e9c16cac..85e247765c35bc 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1403,7 +1403,7 @@ These can be used as types in annotations. They all support subscription using ] However, this does not apply to ``Annotated`` types referenced through a type - alias:: + alias, to avoid forcing evaluation of the underlying :class:`TypeAliasType`:: type From3To10[T] = Annotated[T, ValueRange(3, 10)] assert Annotated[From3To10[int], ctype("char")] != Annotated[ diff --git a/Lib/typing.py b/Lib/typing.py index 79b3e84c071171..4ee53995a61b21 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2240,7 +2240,8 @@ def Annotated(self, *params): assert Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] However, this does not apply to Annotated types referenced through - a type alias:: + a type alias, to avoid forcing evaluation of the underlying + TypeAliasType:: type A[T] = Annotated[T, Ann1, Ann2] assert Annotated[A[T], Ann3] != Annotated[T, Ann1, Ann2, Ann3] From 0885a93359f9efa55320ff326bb58b8ae8f76ef2 Mon Sep 17 00:00:00 2001 From: Valentin Berlier Date: Fri, 14 Feb 2025 20:51:34 +0100 Subject: [PATCH 3/6] Same improvement to the documentation of Union and Literal --- Doc/library/typing.rst | 33 +++++++++++++++++++++++++++++++++ Lib/typing.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 85e247765c35bc..633ff9ee718202 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1098,6 +1098,12 @@ These can be used as types in annotations. They all support subscription using Union[Union[int, str], float] == Union[int, str, float] + However, this does not apply to unions referenced through a type + alias, to avoid forcing evaluation of the underlying :class:`TypeAliasType`:: + + type A = Union[int, str] + Union[A, float] != Union[int, str, float] + * Unions of a single argument vanish, e.g.:: Union[int] == int # The constructor actually returns int @@ -1222,6 +1228,33 @@ These can be used as types in annotations. They all support subscription using is allowed as type argument to ``Literal[...]``, but type checkers may impose restrictions. See :pep:`586` for more details about literal types. + ``Literal`` is very similar to :class:`Union`, the main difference is that its + arguments are literal values instead of types: + + * The arguments must be literal values and there must be at least one. + + * Nested ``Literal`` types are flattened, e.g.:: + + assert Literal[Literal[1, 2], 3] == Literal[1, 2, 3] + + However, this does not apply to ``Literal`` types referenced through a type + alias, to avoid forcing evaluation of the underlying :class:`TypeAliasType`:: + + type A = Literal[1, 2] + assert Literal[A, 3] != Literal[1, 2, 3] + + * Redundant arguments are skipped, e.g.:: + + assert Union[1, 2, 1] == Union[1, 2] + + * When comparing literals, the argument order is ignored, e.g.:: + + assert Literal[1, 2] == Literal[2, 1] + + * You cannot subclass or instantiate a ``Literal``. + + * You cannot write ``Literal[X][Y]``. + .. versionadded:: 3.8 .. versionchanged:: 3.9.1 diff --git a/Lib/typing.py b/Lib/typing.py index 4ee53995a61b21..1f3002c35a824c 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -765,6 +765,13 @@ def Union(self, parameters): assert Union[Union[int, str], float] == Union[int, str, float] + However, this does not apply to unions referenced through a type + alias, to avoid forcing evaluation of the underlying + TypeAliasType:: + + type A = Union[int, str] + assert Union[A, float] != Union[int, str, float] + - Unions of a single argument vanish, e.g.:: assert Union[int] == int # The constructor actually returns int @@ -830,6 +837,33 @@ def open_helper(file: str, mode: MODE) -> str: Literal[...] cannot be subclassed. At runtime, an arbitrary value is allowed as type argument to Literal[...], but type checkers may impose restrictions. + + Literal is very similar to Union, the main difference is that its + arguments are literal values instead of types: + + - The arguments must be literal values and there must be at least one. + + - Nested Literal types are flattened, e.g.:: + + assert Literal[Literal[1, 2], 3] == Literal[1, 2, 3] + + However, this does not apply to Literal types referenced through a type + alias, to avoid forcing evaluation of the underlying TypeAliasType:: + + type A = Literal[1, 2] + assert Literal[A, 3] != Literal[1, 2, 3] + + - Redundant arguments are skipped, e.g.:: + + assert Union[1, 2, 1] == Union[1, 2] + + - When comparing literals, the argument order is ignored, e.g.:: + + assert Literal[1, 2] == Literal[2, 1] + + - You cannot subclass or instantiate a Literal. + + - You cannot write Literal[X][Y]. """ # There is no '_type_check' call because arguments to Literal[...] are # values, not types. From 57b32a46c67ddb30b9af6f7f481e543629ef36b2 Mon Sep 17 00:00:00 2001 From: Valentin Berlier Date: Tue, 4 Mar 2025 00:33:47 +0100 Subject: [PATCH 4/6] Revert all docstring changes --- Lib/typing.py | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 1f3002c35a824c..66570db7a5bd74 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -765,13 +765,6 @@ def Union(self, parameters): assert Union[Union[int, str], float] == Union[int, str, float] - However, this does not apply to unions referenced through a type - alias, to avoid forcing evaluation of the underlying - TypeAliasType:: - - type A = Union[int, str] - assert Union[A, float] != Union[int, str, float] - - Unions of a single argument vanish, e.g.:: assert Union[int] == int # The constructor actually returns int @@ -837,33 +830,6 @@ def open_helper(file: str, mode: MODE) -> str: Literal[...] cannot be subclassed. At runtime, an arbitrary value is allowed as type argument to Literal[...], but type checkers may impose restrictions. - - Literal is very similar to Union, the main difference is that its - arguments are literal values instead of types: - - - The arguments must be literal values and there must be at least one. - - - Nested Literal types are flattened, e.g.:: - - assert Literal[Literal[1, 2], 3] == Literal[1, 2, 3] - - However, this does not apply to Literal types referenced through a type - alias, to avoid forcing evaluation of the underlying TypeAliasType:: - - type A = Literal[1, 2] - assert Literal[A, 3] != Literal[1, 2, 3] - - - Redundant arguments are skipped, e.g.:: - - assert Union[1, 2, 1] == Union[1, 2] - - - When comparing literals, the argument order is ignored, e.g.:: - - assert Literal[1, 2] == Literal[2, 1] - - - You cannot subclass or instantiate a Literal. - - - You cannot write Literal[X][Y]. """ # There is no '_type_check' call because arguments to Literal[...] are # values, not types. @@ -2273,13 +2239,6 @@ def Annotated(self, *params): assert Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - However, this does not apply to Annotated types referenced through - a type alias, to avoid forcing evaluation of the underlying - TypeAliasType:: - - type A[T] = Annotated[T, Ann1, Ann2] - assert Annotated[A[T], Ann3] != Annotated[T, Ann1, Ann2, Ann3] - - Instantiating an annotated type is equivalent to instantiating the underlying type:: From fd75adf598e84f61d6ba8b3ac41f2666fc00bc69 Mon Sep 17 00:00:00 2001 From: Valentin Berlier Date: Tue, 4 Mar 2025 00:37:04 +0100 Subject: [PATCH 5/6] Do not draw comparisons between Literal and Union --- Doc/library/typing.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 633ff9ee718202..2a26f361bd1e8f 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1228,8 +1228,7 @@ These can be used as types in annotations. They all support subscription using is allowed as type argument to ``Literal[...]``, but type checkers may impose restrictions. See :pep:`586` for more details about literal types. - ``Literal`` is very similar to :class:`Union`, the main difference is that its - arguments are literal values instead of types: + Additional details: * The arguments must be literal values and there must be at least one. From 511797c735d53d39f59e3cb5836fc49bff22449d Mon Sep 17 00:00:00 2001 From: Valentin Berlier Date: Mon, 5 May 2025 13:16:23 +0200 Subject: [PATCH 6/6] Fix typo Union -> Literal Co-authored-by: Jelle Zijlstra --- Doc/library/typing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 2a26f361bd1e8f..8dbfae805cd0c0 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1244,7 +1244,7 @@ These can be used as types in annotations. They all support subscription using * Redundant arguments are skipped, e.g.:: - assert Union[1, 2, 1] == Union[1, 2] + assert Literal[1, 2, 1] == Literal[1, 2] * When comparing literals, the argument order is ignored, e.g.::