Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
======================
Expand Down
40 changes: 40 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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__."""

Expand Down
16 changes: 16 additions & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
'runtime_checkable',
'Text',
'TYPE_CHECKING',
'TypeAlias',
]

# The pseudo-submodules 're' and 'io' are part of the public
Expand Down Expand Up @@ -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."""

Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ Christoph Gohlke
Tim Golden
Yonatan Goldschmidt
Mark Gollahon
Mikhail Golubev
Guilherme Gonçalves
Tiago Gonçalves
Chris Gonnerman
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement :pep:`613`, introducing :class:`typing.TypeAlias` annotation.