From c15b70610400ffb4233462534ee081841ce8682d Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Sat, 3 Oct 2020 19:42:35 +0300 Subject: [PATCH 1/3] bpo-41923: PEP 613: Add TypeAlias to typing module This special marker annotation is intended to help in distinguishing proper PEP 484-compliant type aliases from regular top-level variable assignments. --- Doc/whatsnew/3.10.rst | 4 ++ Lib/test/test_typing.py | 40 +++++++++++++++++++ Lib/typing.py | 16 ++++++++ Misc/ACKS | 1 + .../2020-10-03-23-14-50.bpo-41923.Buonw9.rst | 1 + 5 files changed, 62 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 957a3e791ecb69..26f3bf4df29783 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -82,6 +82,10 @@ New Features * :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used to require that all the iterables have an equal length. +* :pep:`613`: The :mod:`typing` module now has a special annotation + :class:`TypeAlias` to explicitly declare :pep:`484`-compliant type aliases, + better differentiating them from regular assignments. + Other Language Changes ====================== diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 42aa430c5e107e..1b53d2472450b6 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -24,6 +24,7 @@ from typing import IO, TextIO, BinaryIO from typing import Pattern, Match from typing import Annotated, ForwardRef +from typing import TypeAlias import abc import typing import weakref @@ -4176,6 +4177,45 @@ def test_annotated_in_other_types(self): self.assertEqual(X[int], List[Annotated[int, 5]]) +class TypeAliasTests(BaseTestCase): + def test_canonical_usage_with_variable_annotation(self): + Alias: TypeAlias = Employee + + def test_canonical_usage_with_type_comment(self): + Alias = Employee # type: TypeAlias + + def test_cannot_instantiate(self): + with self.assertRaises(TypeError): + TypeAlias() + + def test_no_isinstance(self): + with self.assertRaises(TypeError): + isinstance(42, TypeAlias) + + def test_no_issubclass(self): + with self.assertRaises(TypeError): + issubclass(Employee, TypeAlias) + + with self.assertRaises(TypeError): + issubclass(TypeAlias, Employee) + + def test_cannot_subclass(self): + with self.assertRaises(TypeError): + class C(TypeAlias): + pass + + with self.assertRaises(TypeError): + class C(type(TypeAlias)): + pass + + def test_repr(self): + self.assertEqual(repr(TypeAlias), 'typing.TypeAlias') + + def test_cannot_subscript(self): + with self.assertRaises(TypeError): + TypeAlias[int] + + class AllTests(BaseTestCase): """Tests for __all__.""" diff --git a/Lib/typing.py b/Lib/typing.py index 8c61bd8e084a85..e7c27ab463af29 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -112,6 +112,7 @@ 'runtime_checkable', 'Text', 'TYPE_CHECKING', + 'TypeAlias', ] # The pseudo-submodules 're' and 'io' are part of the public @@ -459,6 +460,21 @@ def open_helper(file: str, mode: MODE) -> str: return _GenericAlias(self, parameters) +@_SpecialForm +def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") + + class ForwardRef(_Final, _root=True): """Internal wrapper to hold a forward reference.""" diff --git a/Misc/ACKS b/Misc/ACKS index 9be0e777ca2942..8623bd15726a59 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -611,6 +611,7 @@ Christoph Gohlke Tim Golden Yonatan Goldschmidt Mark Gollahon +Mikhail Golubev Guilherme Gonçalves Tiago Gonçalves Chris Gonnerman diff --git a/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst b/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst new file mode 100644 index 00000000000000..9d35991f70e7b7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst @@ -0,0 +1 @@ +Implement :pep:`613`, introducing :class:`typing.TypeAlias` annotation. From c49533f3e066492fe95b7e0ae5312bd571feb210 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 6 Oct 2020 23:02:12 +0300 Subject: [PATCH 2/3] Draft the bare-bones documentation for TypeAlias --- Doc/library/typing.rst | 13 +++++++++++ Doc/whatsnew/3.10.rst | 23 ++++++++++++++++--- .../2020-10-03-23-14-50.bpo-41923.Buonw9.rst | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a72632e61b0730..f4b2718cdc2f8c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -34,6 +34,8 @@ In the function ``greeting``, the argument ``name`` is expected to be of type :class:`str` and the return type :class:`str`. Subtypes are accepted as arguments. +.. _type-aliases: + Type aliases ============ @@ -489,6 +491,17 @@ These can be used as types in annotations and do not support ``[]``. .. versionadded:: 3.5.4 .. versionadded:: 3.6.2 +.. data:: TypeAlias + + Special annotation for explicitly declaring a :ref:`type alias `. + For example:: + + from typing import TypeAlias + + Factors: TypeAlias = list[int] + + .. versionadded:: 3.10 + Special forms """"""""""""" diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 9db436fc1e8a43..42747993e92f65 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -82,9 +82,26 @@ New Features * :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used to require that all the iterables have an equal length. -* :pep:`613`: The :mod:`typing` module now has a special annotation - :class:`TypeAlias` to explicitly declare :pep:`484`-compliant type aliases, - better differentiating them from regular assignments. +PEP613: TypeAlias Annotation +---------------------------- + +:pep:`484` introduced the concept of type aliases, only requiring them to be +top-level unannotated assignments. This simplicity sometimes made it difficult +for type checkers to distinguish between type aliases and ordinary assignments, +especially when forward references or invalid types were involved. Compare:: + + StrCache = 'Cache[str]' # a type alias + LOG_PREFIX = 'LOG[DEBUG]' # a module constant + +Now the :mod:`typing` module has a special annotation :data:`TypeAlias` to +declare type aliases more explicitly:: + + StrCache: TypeAlias = 'Cache[str]' # a type alias + LOG_PREFIX = 'LOG[DEBUG]' # a module constant + +See :pep:`613` for more details. + +(Contributed by Mikhail Golubev in :issue:`41923`.) PEP604: New Type Operator ------------------------- diff --git a/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst b/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst index 9d35991f70e7b7..dd9a1f709f33ff 100644 --- a/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst +++ b/Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst @@ -1 +1 @@ -Implement :pep:`613`, introducing :class:`typing.TypeAlias` annotation. +Implement :pep:`613`, introducing :data:`typing.TypeAlias` annotation. From 1c2fecffbcc4fbb7224362dc37dc66c36afd1908 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 7 Oct 2020 14:16:32 -0700 Subject: [PATCH 3/3] Fix PEPNNN heading titles These should be PEP NNN. --- Doc/whatsnew/3.10.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 42747993e92f65..835904af7113e9 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -82,8 +82,8 @@ New Features * :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used to require that all the iterables have an equal length. -PEP613: TypeAlias Annotation ----------------------------- +PEP 613: TypeAlias Annotation +----------------------------- :pep:`484` introduced the concept of type aliases, only requiring them to be top-level unannotated assignments. This simplicity sometimes made it difficult @@ -103,8 +103,8 @@ See :pep:`613` for more details. (Contributed by Mikhail Golubev in :issue:`41923`.) -PEP604: New Type Operator -------------------------- +PEP604: New Type Union Operator +------------------------------- A new type union operator was introduced which enables the syntax ``X | Y``. This provides a cleaner way of expressing 'either type X or type Y' instead of