[Python-checkins] bpo-41923: PEP 613: Add TypeAlias to typing module (#22532)

Mikhail Golubev webhook-mailer at python.org
Wed Oct 7 17:44:50 EDT 2020


https://github.com/python/cpython/commit/4f3c25043d651a13c41cffcee703f7d5cb677cc7
commit: 4f3c25043d651a13c41cffcee703f7d5cb677cc7
branch: master
author: Mikhail Golubev <qsolo825 at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-10-07T14:44:31-07:00
summary:

bpo-41923: PEP 613: Add TypeAlias to typing module (#22532)

This special marker annotation is intended to help in distinguishing
proper PEP 484-compliant type aliases from regular top-level variable
assignments.

files:
A Misc/NEWS.d/next/Library/2020-10-03-23-14-50.bpo-41923.Buonw9.rst
M Doc/library/typing.rst
M Doc/whatsnew/3.10.rst
M Lib/test/test_typing.py
M Lib/typing.py
M Misc/ACKS

diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index a72632e61b073..f4b2718cdc2f8 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 <type-aliases>`.
+   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 2bcdba69957b6..4ada4be3b6671 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -99,8 +99,29 @@ in :issue:`38605`.)
 * :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used
   to require that all the iterables have an equal length.
 
-PEP604: New Type Operator
--------------------------
+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
+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 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
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 4bef42f4f32fc..57dd73c529da5 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 4cf33c1ae9265..0f457ab1f56df 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -113,6 +113,7 @@
     'runtime_checkable',
     'Text',
     'TYPE_CHECKING',
+    'TypeAlias',
 ]
 
 # The pseudo-submodules 're' and 'io' are part of the public
@@ -460,6 +461,21 @@ def open_helper(file: str, mode: MODE) -> str:
     return _GenericAlias(self, parameters)
 
 
+ at _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 08449fe08269b..7d445c5721455 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 0000000000000..dd9a1f709f33f
--- /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 :data:`typing.TypeAlias` annotation.



More information about the Python-checkins mailing list