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.
This commit is contained in:
parent
f90dc36c15
commit
4f3c25043d
|
@ -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
|
:class:`str` and the return type :class:`str`. Subtypes are accepted as
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
|
.. _type-aliases:
|
||||||
|
|
||||||
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.5.4
|
||||||
.. versionadded:: 3.6.2
|
.. 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
|
Special forms
|
||||||
"""""""""""""
|
"""""""""""""
|
||||||
|
|
||||||
|
|
|
@ -99,8 +99,29 @@ in :issue:`38605`.)
|
||||||
* :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used
|
* :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used
|
||||||
to require that all the iterables have an equal length.
|
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``.
|
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
|
This provides a cleaner way of expressing 'either type X or type Y' instead of
|
||||||
|
|
|
@ -24,6 +24,7 @@ from typing import NamedTuple, TypedDict
|
||||||
from typing import IO, TextIO, BinaryIO
|
from typing import IO, TextIO, BinaryIO
|
||||||
from typing import Pattern, Match
|
from typing import Pattern, Match
|
||||||
from typing import Annotated, ForwardRef
|
from typing import Annotated, ForwardRef
|
||||||
|
from typing import TypeAlias
|
||||||
import abc
|
import abc
|
||||||
import typing
|
import typing
|
||||||
import weakref
|
import weakref
|
||||||
|
@ -4176,6 +4177,45 @@ class AnnotatedTests(BaseTestCase):
|
||||||
self.assertEqual(X[int], List[Annotated[int, 5]])
|
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):
|
class AllTests(BaseTestCase):
|
||||||
"""Tests for __all__."""
|
"""Tests for __all__."""
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ __all__ = [
|
||||||
'runtime_checkable',
|
'runtime_checkable',
|
||||||
'Text',
|
'Text',
|
||||||
'TYPE_CHECKING',
|
'TYPE_CHECKING',
|
||||||
|
'TypeAlias',
|
||||||
]
|
]
|
||||||
|
|
||||||
# The pseudo-submodules 're' and 'io' are part of the public
|
# The pseudo-submodules 're' and 'io' are part of the public
|
||||||
|
@ -460,6 +461,21 @@ def Literal(self, parameters):
|
||||||
return _GenericAlias(self, parameters)
|
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):
|
class ForwardRef(_Final, _root=True):
|
||||||
"""Internal wrapper to hold a forward reference."""
|
"""Internal wrapper to hold a forward reference."""
|
||||||
|
|
||||||
|
|
|
@ -611,6 +611,7 @@ Christoph Gohlke
|
||||||
Tim Golden
|
Tim Golden
|
||||||
Yonatan Goldschmidt
|
Yonatan Goldschmidt
|
||||||
Mark Gollahon
|
Mark Gollahon
|
||||||
|
Mikhail Golubev
|
||||||
Guilherme Gonçalves
|
Guilherme Gonçalves
|
||||||
Tiago Gonçalves
|
Tiago Gonçalves
|
||||||
Chris Gonnerman
|
Chris Gonnerman
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Implement :pep:`613`, introducing :data:`typing.TypeAlias` annotation.
|
Loading…
Reference in New Issue