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
40 changes: 39 additions & 1 deletion typing_extensions/src_py2/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from typing_extensions import Annotated, NoReturn, ClassVar, IntVar
from typing_extensions import ContextManager, Counter, Deque, DefaultDict
from typing_extensions import NewType, overload
from typing_extensions import NewType, TypeAlias, overload
from typing import Dict, List
import typing
import typing_extensions
Expand Down Expand Up @@ -377,6 +377,44 @@ def test_annotated_in_other_types(self):
self.assertEqual(X[int], List[Annotated[int, 5]])


class TypeAliasTests(BaseTestCase):
Comment thread
gvanrossum marked this conversation as resolved.
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):
if hasattr(typing, 'TypeAlias'):
self.assertEqual(repr(TypeAlias), 'typing.TypeAlias')
self.assertEqual(repr(type(TypeAlias)), 'typing.TypeAlias')
else:
self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias')
self.assertEqual(repr(type(TypeAlias)), 'typing_extensions.TypeAlias')

def test_cannot_subscript(self):
with self.assertRaises(TypeError):
TypeAlias[int]


class AllTests(BaseTestCase):

def test_typing_extensions_includes_standard(self):
Expand Down
38 changes: 38 additions & 0 deletions typing_extensions/src_py2/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,43 @@ class Annotated(object):
__slots__ = ()


class _TypeAliasMeta(typing.TypingMeta):
"""Metaclass for TypeAlias"""

def __new__(cls, name, bases, namespace):
cls.assert_no_subclassing(bases)
self = super(_TypeAliasMeta, cls).__new__(cls, name, bases, namespace)
return self

def __repr__(self):
return 'typing_extensions.TypeAlias'


class _TypeAliasBase(typing._FinalTypingBase):
"""Special marker indicating that an assignment should
be recognized as a proper type alias definition by type
checkers.

For example::

Predicate = Callable[[...], bool] # type: TypeAlias

It's invalid when used anyhow but as in the example above.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anyhow but -> anywhere except

"""
__metaclass__ = _TypeAliasMeta
__slots__ = ()

def __instancecheck__(self, obj):
raise TypeError("TypeAlias cannot be used with isinstance().")

def __subclasscheck__(self, cls):
raise TypeError("TypeAlias cannot be used with issubclass().")

def __repr__(self):
return 'typing_extensions.TypeAlias'


TypeAlias = _TypeAliasBase(_root=True)

# This alias exists for backwards compatibility.
runtime = runtime_checkable
39 changes: 39 additions & 0 deletions typing_extensions/src_py3/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from typing import Generic
from typing import no_type_check
from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict
from typing_extensions import TypeAlias
try:
from typing_extensions import Protocol, runtime, runtime_checkable
except ImportError:
Expand Down Expand Up @@ -1822,6 +1823,44 @@ def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]":
)


class TypeAliasTests(BaseTestCase):
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)

if SUBCLASS_CHECK_FORBIDDEN:
with self.assertRaises(TypeError):
issubclass(TypeAlias, Employee)

def test_cannot_subclass(self):
with self.assertRaises(TypeError):
class C(TypeAlias):
pass

if SUBCLASS_CHECK_FORBIDDEN:
with self.assertRaises(TypeError):
class C(type(TypeAlias)):
pass

def test_repr(self):
if hasattr(typing, 'TypeAlias'):
self.assertEqual(repr(TypeAlias), 'typing.TypeAlias')
else:
self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias')

def test_cannot_subscript(self):
with self.assertRaises(TypeError):
TypeAlias[int]


class AllTests(BaseTestCase):

def test_typing_extensions_includes_standard(self):
Expand Down
97 changes: 97 additions & 0 deletions typing_extensions/src_py3/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2071,3 +2071,100 @@ def get_args(tp):
res = (list(res[:-1]), res[-1])
return res
return ()


if hasattr(typing, 'TypeAlias'):
TypeAlias = typing.TypeAlias
elif sys.version_info[:2] >= (3, 9):
class _TypeAliasForm(typing._SpecialForm, _root=True):
def __repr__(self):
return 'typing_extensions.' + self._name

@_TypeAliasForm
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 anyhow but as in the example above.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anyhow as -> anywhere except

"""
raise TypeError("{} is not subscriptable".format(self))

elif sys.version_info[:2] >= (3, 7):
class _TypeAliasForm(typing._SpecialForm, _root=True):
def __repr__(self):
return 'typing_extensions.' + self._name


TypeAlias = _TypeAliasForm('TypeAlias', doc=
"""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 anyhow but as in the example above.
""")

elif hasattr(typing, '_FinalTypingBase'):
class _TypeAliasMeta(typing.TypingMeta):
"""Metaclass for TypeAlias"""

def __repr__(self):
return 'typing_extensions.TypeAlias'

class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True):
"""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 anyhow but as in the example above.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(again)

"""
__slots__ = ()

def __instancecheck__(self, obj):
raise TypeError("TypeAlias cannot be used with isinstance().")

def __subclasscheck__(self, cls):
raise TypeError("TypeAlias cannot be used with issubclass().")

def __repr__(self):
return 'typing_extensions.TypeAlias'

TypeAlias = _TypeAliasBase(_root=True)
else:
class _TypeAliasMeta(typing.TypingMeta):
"""Metaclass for TypeAlias"""

def __instancecheck__(self, obj):
raise TypeError("TypeAlias cannot be used with isinstance().")

def __subclasscheck__(self, cls):
raise TypeError("TypeAlias cannot be used with issubclass().")

def __call__(self, *args, **kwargs):
raise TypeError("Cannot instantiate TypeAlias")


class TypeAlias(metaclass=_TypeAliasMeta, _root=True):
"""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 anyhow but as in the example above.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(ditto)

"""
__slots__ = ()