From f5ee89b21bdc144ee5de53ae982c320f38c667b8 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 11 Nov 2021 16:58:29 +0000 Subject: [PATCH 01/12] Drop declared support for Python 3.6 --- .github/workflows/ci.yml | 2 +- CONTRIBUTING.md | 2 +- typing_extensions/CHANGELOG | 16 ++++++++++++++++ typing_extensions/pyproject.toml | 7 +++---- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80b40924..61150f08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10"] runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f76b51df..0dc1d19a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ standard library, so that users can experiment with them before they are added t standard library. Such features should ideally already be specified in a PEP or draft PEP. -`typing_extensions` supports Python versions 3.6 and up. +`typing_extensions` supports Python versions 3.7 and up. # Versioning scheme diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG index 24fe698d..fb46b9d5 100644 --- a/typing_extensions/CHANGELOG +++ b/typing_extensions/CHANGELOG @@ -1,3 +1,19 @@ +# Changes in version 5.0.0 + +Dropped support for Python 3.6 and simplified backports for Python 3.7.0 and +newer. Patch by Adam Turner (@AA-Turner). + +## Removed in version 5.0.0 + +The following non-exported but non-private names have been removed as they are +unneeded for supporting Python 3.7 and newer. + +- PEP_560 +- GenericMeta +- T +- T_co +- T_contra + # Release 4.0.1 (November 30, 2021) - Fix broken sdist in release 4.0.0. Patch by Adam Turner (@AA-Turner). diff --git a/typing_extensions/pyproject.toml b/typing_extensions/pyproject.toml index 073444a8..8b22e6e3 100644 --- a/typing_extensions/pyproject.toml +++ b/typing_extensions/pyproject.toml @@ -6,8 +6,8 @@ build-backend = "flit_core.buildapi" # Project metadata [project] name = "typing_extensions" -version = "4.0.1" -description = "Backported and Experimental Type Hints for Python 3.6+" +version = "5.0.0" +description = "Backported and Experimental Type Hints for Python 3.7+" readme.text = """\ Typing Extensions -- Backported and Experimental Type Hints for Python @@ -22,7 +22,7 @@ Experimental types that may eventually be added to the ``typing`` module are also included in ``typing_extensions``. """ readme.content-type = "text/x-rst" -requires-python = ">=3.6" +requires-python = ">=3.7" urls.Home = "https://github.com/python/typing/blob/master/typing_extensions/README.rst" license.file = "LICENSE" keywords = [ @@ -48,7 +48,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", From 4632da1b57a722a650404cf0067d8b82e384ca80 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 11 Nov 2021 17:02:11 +0000 Subject: [PATCH 02/12] Drop Python 3.6 support --- .../src/test_typing_extensions.py | 97 +- typing_extensions/src/typing_extensions.py | 994 +----------------- 2 files changed, 47 insertions(+), 1044 deletions(-) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index 731f9731..a568e873 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -7,7 +7,7 @@ import pickle import subprocess import types -from unittest import TestCase, main, skipUnless, skipIf +from unittest import TestCase, main, skipIf from test import ann_module, ann_module2, ann_module3 import typing from typing import TypeVar, Optional, Union @@ -20,31 +20,13 @@ from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload -try: - from typing_extensions import get_type_hints -except ImportError: - from typing import get_type_hints - -PEP_560 = sys.version_info[:3] >= (3, 7, 0) - -OLD_GENERICS = False -try: - from typing import _type_vars, _next_in_mro, _type_check # noqa -except ImportError: - OLD_GENERICS = True +from typing_extensions import get_type_hints # Flags used to mark tests that only apply after a specific # version of the typing module. -TYPING_3_6_1 = sys.version_info[:3] >= (3, 6, 1) TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0) TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0) -# For typing versions where instantiating collection -# types are allowed. -# -# See https://github.com/python/typing/issues/367 -CAN_INSTANTIATE_COLLECTIONS = TYPING_3_6_1 - class BaseTestCase(TestCase): def assertIsSubclass(self, cls, class_or_tuple, msg=None): @@ -160,7 +142,7 @@ def test_basics(self): Final[int][str] def test_repr(self): - if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + if hasattr(typing, 'Final'): mod_name = 'typing' else: mod_name = 'typing_extensions' @@ -543,7 +525,6 @@ def test_final_forward_ref(self): self.assertNotEqual(gth(Loop, globals())['attr'], Final) -@skipUnless(PEP_560, "Python 3.7+ required") class GetUtilitiesTestCase(TestCase): def test_get_origin(self): from typing_extensions import get_origin @@ -679,7 +660,6 @@ class MyDeque(typing_extensions.Deque[int]): ... def test_counter(self): self.assertIsSubclass(collections.Counter, typing_extensions.Counter) - @skipUnless(CAN_INSTANTIATE_COLLECTIONS, "Behavior added in typing 3.6.1") def test_defaultdict_instantiation(self): self.assertIs( type(typing_extensions.DefaultDict()), @@ -702,7 +682,6 @@ class MyDefDict(typing_extensions.DefaultDict[str, int]): self.assertIsSubclass(MyDefDict, collections.defaultdict) self.assertNotIsSubclass(collections.defaultdict, MyDefDict) - @skipUnless(CAN_INSTANTIATE_COLLECTIONS, "Behavior added in typing 3.6.1") def test_ordereddict_instantiation(self): self.assertIs( type(typing_extensions.OrderedDict()), @@ -756,10 +735,7 @@ def test_counter_instantiation(self): self.assertIs(type(typing_extensions.Counter[int]()), collections.Counter) class C(typing_extensions.Counter[T]): ... self.assertIs(type(C[int]()), C) - if not PEP_560: - self.assertEqual(C.__bases__, (typing_extensions.Counter,)) - else: - self.assertEqual(C.__bases__, (collections.Counter, typing.Generic)) + self.assertEqual(C.__bases__, (collections.Counter, typing.Generic)) def test_counter_subclass_instantiation(self): @@ -834,9 +810,8 @@ def manager(): cm = manager() self.assertNotIsInstance(cm, typing_extensions.AsyncContextManager) self.assertEqual(typing_extensions.AsyncContextManager[int].__args__, (int,)) - if TYPING_3_6_1: - with self.assertRaises(TypeError): - isinstance(42, typing_extensions.AsyncContextManager[int]) + with self.assertRaises(TypeError): + isinstance(42, typing_extensions.AsyncContextManager[int]) with self.assertRaises(TypeError): typing_extensions.AsyncContextManager[int, str] @@ -1101,10 +1076,6 @@ def x(self): ... self.assertIsSubclass(C, P) self.assertIsSubclass(C, PG) self.assertIsSubclass(BadP, PG) - if not PEP_560: - self.assertIsSubclass(PG[int], PG) - self.assertIsSubclass(BadPG[int], P) - self.assertIsSubclass(BadPG[T], PG) with self.assertRaises(TypeError): issubclass(C, PG[T]) with self.assertRaises(TypeError): @@ -1295,28 +1266,6 @@ class C: pass with self.assertRaises(TypeError): issubclass(C(), P) - @skipUnless(not OLD_GENERICS, "New style generics required") - def test_defining_generic_protocols(self): - T = TypeVar('T') - S = TypeVar('S') - @runtime - class PR(Protocol[T, S]): - def meth(self): pass - class P(PR[int, T], Protocol[T]): - y = 1 - self.assertIsSubclass(PR[int, T], PR) - self.assertIsSubclass(P[str], PR) - with self.assertRaises(TypeError): - PR[int] - with self.assertRaises(TypeError): - P[int, str] - with self.assertRaises(TypeError): - PR[int, 1] - with self.assertRaises(TypeError): - PR[int, ClassVar] - class C(PR[int, T]): pass - self.assertIsInstance(C[str](), C) - def test_defining_generic_protocols_old_style(self): T = TypeVar('T') S = TypeVar('S') @@ -1325,11 +1274,8 @@ class PR(Protocol, Generic[T, S]): def meth(self): pass class P(PR[int, str], Protocol): y = 1 - if not PEP_560: + with self.assertRaises(TypeError): self.assertIsSubclass(PR[int, str], PR) - else: - with self.assertRaises(TypeError): - self.assertIsSubclass(PR[int, str], PR) self.assertIsSubclass(P, PR) with self.assertRaises(TypeError): PR[int] @@ -1360,7 +1306,6 @@ def __init__(self): self.test = 'OK' self.assertEqual(C[int]().test, 'OK') - @skipUnless(not OLD_GENERICS, "New style generics required") def test_protocols_bad_subscripts(self): T = TypeVar('T') S = TypeVar('S') @@ -1377,9 +1322,6 @@ def test_generic_protocols_repr(self): T = TypeVar('T') S = TypeVar('S') class P(Protocol[T, S]): pass - # After PEP 560 unsubscripted generics have a standard repr. - if not PEP_560: - self.assertTrue(repr(P).endswith('P')) self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) @@ -1392,17 +1334,6 @@ class P(Protocol[T, S]): pass self.assertEqual(P[T, T][Tuple[T, S]][int, str], P[Tuple[int, str], Tuple[int, str]]) - @skipUnless(not OLD_GENERICS, "New style generics required") - def test_generic_protocols_special_from_generic(self): - T = TypeVar('T') - class P(Protocol[T]): pass - self.assertEqual(P.__parameters__, (T,)) - self.assertIs(P.__args__, None) - self.assertIs(P.__origin__, None) - self.assertEqual(P[int].__parameters__, ()) - self.assertEqual(P[int].__args__, (int,)) - self.assertIs(P[int].__origin__, P) - def test_generic_protocols_special_from_protocol(self): @runtime class PR(Protocol): @@ -1429,9 +1360,6 @@ def meth(self): self.assertEqual(typing_extensions._get_protocol_attrs(PR), {'x'}) self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG)), frozenset({'x', 'meth'})) - if not PEP_560: - self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG[int])), - frozenset({'x', 'meth'})) def test_no_runtime_deco_on_nominal(self): with self.assertRaises(TypeError): @@ -1702,16 +1630,14 @@ def test_flatten(self): A = Annotated[Annotated[int, 4], 5] self.assertEqual(A, Annotated[int, 4, 5]) self.assertEqual(A.__metadata__, (4, 5)) - if PEP_560: - self.assertEqual(A.__origin__, int) + self.assertEqual(A.__origin__, int) def test_specialize(self): L = Annotated[List[T], "my decoration"] LI = Annotated[List[int], "my decoration"] self.assertEqual(L[int], Annotated[List[int], "my decoration"]) self.assertEqual(L[int].__metadata__, ("my decoration",)) - if PEP_560: - self.assertEqual(L[int].__origin__, List[int]) + self.assertEqual(L[int].__origin__, List[int]) with self.assertRaises(TypeError): LI[int] with self.assertRaises(TypeError): @@ -1797,7 +1723,6 @@ def test_cannot_check_subclass(self): with self.assertRaises(TypeError): issubclass(int, Annotated[int, "positive"]) - @skipUnless(PEP_560, "pickle support was added with PEP 560") def test_pickle(self): samples = [typing.Any, typing.Union[int, str], typing.Optional[str], Tuple[int, ...], @@ -1862,7 +1787,6 @@ def test_annotated_in_other_types(self): self.assertEqual(X[int], List[Annotated[int, 5]]) -@skipUnless(PEP_560, "Python 3.7 required") class GetTypeHintsTests(BaseTestCase): def test_get_type_hints(self): def foobar(x: List['X']): ... @@ -2225,8 +2149,7 @@ def test_typing_extensions_includes_standard(self): self.assertIn("Concatenate", a) self.assertIn('Annotated', a) - if PEP_560: - self.assertIn('get_type_hints', a) + self.assertIn('get_type_hints', a) self.assertIn('Awaitable', a) self.assertIn('AsyncIterator', a) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index 455e3195..286771cf 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -5,29 +5,9 @@ import sys import typing -# After PEP 560, internal typing API was substantially reworked. -# This is especially important for Protocol class which uses internal APIs -# quite extensively. -PEP_560 = sys.version_info[:3] >= (3, 7, 0) - -if PEP_560: - GenericMeta = type -else: - # 3.6 - from typing import GenericMeta, _type_vars # noqa - -# The two functions below are copies of typing internal helpers. -# They are needed by _ProtocolMeta - - -def _no_slots_copy(dct): - dict_copy = dict(dct) - if '__slots__' in dict_copy: - for slot in dict_copy['__slots__']: - dict_copy.pop(slot, None) - return dict_copy - +# The function below is a copy of typing internal helpers. +# It is needed by _ProtocolMeta def _check_generic(cls, parameters): if not cls.__parameters__: raise TypeError(f"{cls} is not a generic class") @@ -71,6 +51,9 @@ def _check_generic(cls, parameters): # One-off things. 'Annotated', 'final', + 'get_args', + 'get_origin', + 'get_type_hints', 'IntVar', 'Literal', 'NewType', @@ -85,52 +68,21 @@ def _check_generic(cls, parameters): 'NoReturn', ] -if PEP_560: - __all__.extend(["get_args", "get_origin", "get_type_hints"]) - -# 3.6.2+ -if hasattr(typing, 'NoReturn'): - NoReturn = typing.NoReturn -# 3.6.0-3.6.1 -else: - class _NoReturn(typing._FinalTypingBase, _root=True): - """Special type indicating functions that never return. - Example:: - - from typing import NoReturn - - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - NoReturn = _NoReturn(_root=True) +NoReturn = typing.NoReturn # Some unconstrained type variables. These are used by the container types. # (These are not for export.) -T = typing.TypeVar('T') # Any type. KT = typing.TypeVar('KT') # Key type. VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. ClassVar = typing.ClassVar # On older versions of typing there is an internal class named "Final". # 3.8+ -if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): +if hasattr(typing, 'Final'): Final = typing.Final # 3.7 -elif sys.version_info[:2] >= (3, 7): +else: class _FinalForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -155,66 +107,11 @@ class FastConnector(Connection): TIMEOUT = 1 # Error reported by type checker There is no runtime checking of these properties.""") -# 3.6 -else: - class _Final(typing._FinalTypingBase, _root=True): - """A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties. - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - f'{cls.__name__[1:]} accepts only single type.'), - _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += f'[{typing._type_repr(self.__type__)}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _Final): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - Final = _Final(_root=True) - # 3.8+ if hasattr(typing, 'final'): final = typing.final -# 3.6-3.7 +# 3.7 else: def final(f): """This decorator can be used to indicate to type checkers that @@ -247,7 +144,7 @@ def IntVar(name): if hasattr(typing, 'Literal'): Literal = typing.Literal # 3.7: -elif sys.version_info[:2] >= (3, 7): +else: class _LiteralForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -269,216 +166,38 @@ def __getitem__(self, parameters): Literal[...] cannot be subclassed. There is no runtime checking verifying that the parameter is actually a value instead of a type.""") -# 3.6: -else: - class _Literal(typing._FinalTypingBase, _root=True): - """A type that can be used to indicate to type checkers that the - corresponding value has a value literally equivalent to the - provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to the - value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime checking - verifying that the parameter is actually a value instead of a type. - """ - - __slots__ = ('__values__',) - - def __init__(self, values=None, **kwds): - self.__values__ = values - - def __getitem__(self, values): - cls = type(self) - if self.__values__ is None: - if not isinstance(values, tuple): - values = (values,) - return cls(values, _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - return self - - def __repr__(self): - r = super().__repr__() - if self.__values__ is not None: - r += f'[{", ".join(map(typing._type_repr, self.__values__))}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__values__)) - def __eq__(self, other): - if not isinstance(other, _Literal): - return NotImplemented - if self.__values__ is not None: - return self.__values__ == other.__values__ - return self is other - - Literal = _Literal(_root=True) - - -_overload_dummy = typing._overload_dummy # noqa overload = typing.overload - # This is not a real generic class. Don't use outside annotations. Type = typing.Type # Various ABCs mimicking those in collections.abc. # A few are simply re-exported for completeness. - - -class _ExtensionsGenericMeta(GenericMeta): - def __subclasscheck__(self, subclass): - """This mimics a more modern GenericMeta.__subclasscheck__() logic - (that does not have problems with recursion) to work around interactions - between collections, typing, and typing_extensions on older - versions of Python, see https://github.com/python/typing/issues/501. - """ - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if not self.__extra__: - return super().__subclasscheck__(subclass) - res = self.__extra__.__subclasshook__(subclass) - if res is not NotImplemented: - return res - if self.__extra__ in subclass.__mro__: - return True - for scls in self.__extra__.__subclasses__(): - if isinstance(scls, GenericMeta): - continue - if issubclass(subclass, scls): - return True - return False - - Awaitable = typing.Awaitable Coroutine = typing.Coroutine AsyncIterable = typing.AsyncIterable AsyncIterator = typing.AsyncIterator - -# 3.6.1+ -if hasattr(typing, 'Deque'): - Deque = typing.Deque -# 3.6.0 -else: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Deque: - return collections.deque(*args, **kwds) - return typing._generic_new(collections.deque, cls, *args, **kwds) - +Deque = typing.Deque ContextManager = typing.ContextManager -# 3.6.2+ -if hasattr(typing, 'AsyncContextManager'): - AsyncContextManager = typing.AsyncContextManager -# 3.6.0-3.6.1 -else: - from _collections_abc import _check_methods as _check_methods_in_mro # noqa - - class AsyncContextManager(typing.Generic[T_co]): - __slots__ = () - - async def __aenter__(self): - return self - - @abc.abstractmethod - async def __aexit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is AsyncContextManager: - return _check_methods_in_mro(C, "__aenter__", "__aexit__") - return NotImplemented - +AsyncContextManager = typing.AsyncContextManager DefaultDict = typing.DefaultDict # 3.7.2+ if hasattr(typing, 'OrderedDict'): OrderedDict = typing.OrderedDict # 3.7.0-3.7.2 -elif (3, 7, 0) <= sys.version_info[:3] < (3, 7, 2): - OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) -# 3.6 -else: - class OrderedDict(collections.OrderedDict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.OrderedDict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is OrderedDict: - return collections.OrderedDict(*args, **kwds) - return typing._generic_new(collections.OrderedDict, cls, *args, **kwds) - -# 3.6.2+ -if hasattr(typing, 'Counter'): - Counter = typing.Counter -# 3.6.0-3.6.1 else: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Counter: - return collections.Counter(*args, **kwds) - return typing._generic_new(collections.Counter, cls, *args, **kwds) - -# 3.6.1+ -if hasattr(typing, 'ChainMap'): - ChainMap = typing.ChainMap -elif hasattr(collections, 'ChainMap'): - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): - - __slots__ = () + OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) - def __new__(cls, *args, **kwds): - if cls._gorg is ChainMap: - return collections.ChainMap(*args, **kwds) - return typing._generic_new(collections.ChainMap, cls, *args, **kwds) - -# 3.6.1+ -if hasattr(typing, 'AsyncGenerator'): - AsyncGenerator = typing.AsyncGenerator -# 3.6.0 -else: - class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], - metaclass=_ExtensionsGenericMeta, - extra=collections.abc.AsyncGenerator): - __slots__ = () +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator NewType = typing.NewType Text = typing.Text TYPE_CHECKING = typing.TYPE_CHECKING - -def _gorg(cls): - """This function exists for compatibility with old typing versions.""" - assert isinstance(cls, GenericMeta) - if hasattr(cls, '_gorg'): - return cls._gorg - while cls.__origin__ is not None: - cls = cls.__origin__ - return cls - - _PROTO_WHITELIST = ['Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', @@ -512,7 +231,7 @@ def _is_callable_members_only(cls): if hasattr(typing, 'Protocol'): Protocol = typing.Protocol # 3.7 -elif PEP_560: +else: from typing import _collect_type_vars # noqa def _no_init(self, *args, **kwargs): @@ -695,250 +414,12 @@ def _proto_hook(other): raise TypeError('Protocols can only inherit from other' f' protocols, got {repr(base)}') cls.__init__ = _no_init -# 3.6 -else: - from typing import _next_in_mro, _type_check # noqa - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(GenericMeta): - """Internal metaclass for Protocol. - - This exists so Protocol classes can be generic without deriving - from Generic. - """ - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): - # This is just a version copied from GenericMeta.__new__ that - # includes "Protocol" special treatment. (Comments removed for brevity.) - assert extra is None # Protocols should not have extra - if tvars is not None: - assert origin is not None - assert all(isinstance(t, typing.TypeVar) for t in tvars), tvars - else: - tvars = _type_vars(bases) - gvars = None - for base in bases: - if base is typing.Generic: - raise TypeError("Cannot inherit from plain Generic") - if (isinstance(base, GenericMeta) and - base.__origin__ in (typing.Generic, Protocol)): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ", ".join(str(t) for t in tvars if t not in gvarset) - s_args = ", ".join(str(g) for g in gvars) - cls_name = "Generic" if any(b.__origin__ is typing.Generic - for b in bases) else "Protocol" - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in {cls_name}[{s_args}]") - tvars = gvars - - initial_bases = bases - if (extra is not None and type(extra) is abc.ABCMeta and - extra not in bases): - bases = (extra,) + bases - bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b - for b in bases) - if any(isinstance(b, GenericMeta) and b is not typing.Generic for b in bases): - bases = tuple(b for b in bases if b is not typing.Generic) - namespace.update({'__origin__': origin, '__extra__': extra}) - self = super(GenericMeta, cls).__new__(cls, name, bases, namespace, - _root=True) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else - _gorg(origin)) - self.__parameters__ = tvars - self.__args__ = tuple(... if a is typing._TypingEllipsis else - () if a is typing._TypingEmpty else - a for a in args) if args else None - self.__next_in_mro__ = _next_in_mro(self) - if orig_bases is None: - self.__orig_bases__ = initial_bases - elif origin is not None: - self._abc_registry = origin._abc_registry - self._abc_cache = origin._abc_cache - if hasattr(self, '_subs_tree'): - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) - return self - - def __init__(cls, *args, **kwargs): - super().__init__(*args, **kwargs) - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol or - isinstance(b, _ProtocolMeta) and - b.__origin__ is Protocol - for b in cls.__bases__) - if cls._is_protocol: - for base in cls.__mro__[1:]: - if not (base in (object, typing.Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, typing.TypingMeta) and base._is_protocol or - isinstance(base, GenericMeta) and - base.__origin__ is typing.Generic): - raise TypeError(f'Protocols can only inherit from other' - f' protocols, got {repr(base)}') - - cls.__init__ = _no_init - - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - def __instancecheck__(self, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(self, '_is_protocol', False) or - _is_callable_members_only(self)) and - issubclass(instance.__class__, self)): - return True - if self._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(self, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(self)): - return True - return super(GenericMeta, self).__instancecheck__(instance) - - def __subclasscheck__(self, cls): - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if (self.__dict__.get('_is_protocol', None) and - not self.__dict__.get('_is_runtime_protocol', None)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return False - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if (self.__dict__.get('_is_runtime_protocol', None) and - not _is_callable_members_only(self)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return super(GenericMeta, self).__subclasscheck__(cls) - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - return super(GenericMeta, self).__subclasscheck__(cls) - - @typing._tp_cache - def __getitem__(self, params): - # We also need to copy this from GenericMeta.__getitem__ to get - # special treatment of "Protocol". (Comments removed for brevity.) - if not isinstance(params, tuple): - params = (params,) - if not params and _gorg(self) is not typing.Tuple: - raise TypeError( - f"Parameter list to {self.__qualname__}[...] cannot be empty") - msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) - if self in (typing.Generic, Protocol): - if not all(isinstance(p, typing.TypeVar) for p in params): - raise TypeError( - f"Parameters to {repr(self)}[...] must all be type variables") - if len(set(params)) != len(params): - raise TypeError( - f"Parameters to {repr(self)}[...] must all be unique") - tvars = params - args = params - elif self in (typing.Tuple, typing.Callable): - tvars = _type_vars(params) - args = params - elif self.__origin__ in (typing.Generic, Protocol): - raise TypeError(f"Cannot subscript already-subscripted {repr(self)}") - else: - _check_generic(self, params) - tvars = _type_vars(params) - args = params - - prepend = (self,) if self.__origin__ is None else () - return self.__class__(self.__name__, - prepend + self.__bases__, - _no_slots_copy(self.__dict__), - tvars=tvars, - args=args, - origin=self, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - class Protocol(metaclass=_ProtocolMeta): - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if _gorg(cls) is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can be used only as a base class") - return typing._generic_new(cls.__next_in_mro__, cls, *args, **kwds) # 3.8+ if hasattr(typing, 'runtime_checkable'): runtime_checkable = typing.runtime_checkable -# 3.6-3.7 +# 3.7 else: def runtime_checkable(cls): """Mark a protocol class as a runtime protocol, so that it @@ -958,11 +439,10 @@ def runtime_checkable(cls): # Exists for backwards compatibility. runtime = runtime_checkable - # 3.8+ if hasattr(typing, 'SupportsIndex'): SupportsIndex = typing.SupportsIndex -# 3.6-3.7 +# 3.7 else: @runtime_checkable class SupportsIndex(Protocol): @@ -1118,8 +598,6 @@ class Point2D(TypedDict): Point2D = TypedDict('Point2D', x=int, y=int, label=str) Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - The class syntax is only supported in Python 3.6+, while two other - syntax forms work for Python 2.7 and 3.2+ """ @@ -1131,7 +609,7 @@ class Point2D(TypedDict): # to work. _AnnotatedAlias = typing._AnnotatedAlias # 3.7-3.8 -elif PEP_560: +else: class _AnnotatedAlias(typing._GenericAlias, _root=True): """Runtime representation of an annotated type. @@ -1274,146 +752,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): if include_extras: return hint return {k: _strip_annotations(t) for k, t in hint.items()} -# 3.6 -else: - - def _is_dunder(name): - """Returns True if name is a __dunder_variable_name__.""" - return len(name) > 4 and name.startswith('__') and name.endswith('__') - - # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality - # checks, argument expansion etc. are done on the _subs_tre. As a result we - # can't provide a get_type_hints function that strips out annotations. - - class AnnotatedMeta(typing.GenericMeta): - """Metaclass for Annotated""" - def __new__(cls, name, bases, namespace, **kwargs): - if any(b is not object for b in bases): - raise TypeError("Cannot subclass " + str(Annotated)) - return super().__new__(cls, name, bases, namespace, **kwargs) - - @property - def __metadata__(self): - return self._subs_tree()[2] - - def _tree_repr(self, tree): - cls, origin, metadata = tree - if not isinstance(origin, tuple): - tp_repr = typing._type_repr(origin) - else: - tp_repr = origin[0]._tree_repr(origin) - metadata_reprs = ", ".join(repr(arg) for arg in metadata) - return f'{cls}[{tp_repr}, {metadata_reprs}]' - - def _subs_tree(self, tvars=None, args=None): # noqa - if self is Annotated: - return Annotated - res = super()._subs_tree(tvars=tvars, args=args) - # Flatten nested Annotated - if isinstance(res[1], tuple) and res[1][0] is Annotated: - sub_tp = res[1][1] - sub_annot = res[1][2] - return (Annotated, sub_tp, sub_annot + res[2]) - return res - - def _get_cons(self): - """Return the class used to create instance of this type.""" - if self.__origin__ is None: - raise TypeError("Cannot get the underlying type of a " - "non-specialized Annotated type.") - tree = self._subs_tree() - while isinstance(tree, tuple) and tree[0] is Annotated: - tree = tree[1] - if isinstance(tree, tuple): - return tree[0] - else: - return tree - - @typing._tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if self.__origin__ is not None: # specializing an instantiated type - return super().__getitem__(params) - elif not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be instantiated " - "with at least two arguments (a type and an " - "annotation).") - else: - msg = "Annotated[t, ...]: t must be a type." - tp = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return self.__class__( - self.__name__, - self.__bases__, - _no_slots_copy(self.__dict__), - tvars=_type_vars((tp,)), - # Metadata is a tuple so it won't be touched by _replace_args et al. - args=(tp, metadata), - origin=self, - ) - - def __call__(self, *args, **kwargs): - cons = self._get_cons() - result = cons(*args, **kwargs) - try: - result.__orig_class__ = self - except AttributeError: - pass - return result - - def __getattr__(self, attr): - # For simplicity we just don't relay all dunder names - if self.__origin__ is not None and not _is_dunder(attr): - return getattr(self._get_cons(), attr) - raise AttributeError(attr) - - def __setattr__(self, attr, value): - if _is_dunder(attr) or attr.startswith('_abc_'): - super().__setattr__(attr, value) - elif self.__origin__ is None: - raise AttributeError(attr) - else: - setattr(self._get_cons(), attr, value) - - def __instancecheck__(self, obj): - raise TypeError("Annotated cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Annotated cannot be used with issubclass().") - - class Annotated(metaclass=AnnotatedMeta): - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type, the remaining - arguments are kept as a tuple in the __metadata__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ # Python 3.8 has get_origin() and get_args() but those implementations aren't # Annotated-aware, so we can't use those. Python 3.9's versions don't support @@ -1422,7 +761,7 @@ class Annotated(metaclass=AnnotatedMeta): get_origin = typing.get_origin get_args = typing.get_args # 3.7-3.9 -elif PEP_560: +else: try: # 3.9+ from typing import _BaseGenericAlias @@ -1504,7 +843,7 @@ def TypeAlias(self, parameters): """ raise TypeError(f"{self} is not subscriptable") # 3.7-3.8 -elif sys.version_info[:2] >= (3, 7): +else: class _TypeAliasForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name @@ -1520,44 +859,12 @@ def __repr__(self): It's invalid when used anywhere except as in the example above.""") -# 3.6 -else: - 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 anywhere except as in the example above. - """ - __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) - # Python 3.10+ has PEP 612 if hasattr(typing, 'ParamSpecArgs'): ParamSpecArgs = typing.ParamSpecArgs ParamSpecKwargs = typing.ParamSpecKwargs -# 3.6-3.9 +# 3.7-3.9 else: class _Immutable: """Mixin to indicate that object should not be copied.""" @@ -1608,9 +915,8 @@ def __repr__(self): # 3.10+ if hasattr(typing, 'ParamSpec'): ParamSpec = typing.ParamSpec -# 3.6-3.9 +# 3.7-3.9 else: - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. class ParamSpec(list): """Parameter specification variable. @@ -1710,28 +1016,17 @@ def __reduce__(self): def __call__(self, *args, **kwargs): pass - if not PEP_560: - # Only needed in 3.6. - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) - -# 3.6-3.9 +# 3.7-3.9 if not hasattr(typing, 'Concatenate'): # Inherits from list as a workaround for Callable checks in Python < 3.9.2. class _ConcatenateGenericAlias(list): # Trick Generic into looking into this for __parameters__. - if PEP_560: - __class__ = typing._GenericAlias - else: - __class__ = typing._TypingBase + __class__ = typing._GenericAlias # Flag in 3.8. _special = False - # Attribute in 3.6 and earlier. - _gorg = typing.Generic def __init__(self, origin, args): super().__init__(args) @@ -1756,14 +1051,8 @@ def __parameters__(self): tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) ) - if not PEP_560: - # Only required in 3.6. - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - typing._get_type_vars(self.__parameters__, tvars) - -# 3.6-3.9 +# 3.7-3.9 @typing._tp_cache def _concatenate_getitem(self, parameters): if parameters == (): @@ -1798,7 +1087,7 @@ def Concatenate(self, parameters): """ return _concatenate_getitem(self, parameters) # 3.7-8 -elif sys.version_info[:2] >= (3, 7): +else: class _ConcatenateForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name @@ -1818,42 +1107,6 @@ def __getitem__(self, parameters): See PEP 612 for detailed information. """) -# 3.6 -else: - class _ConcatenateAliasMeta(typing.TypingMeta): - """Metaclass for Concatenate.""" - - def __repr__(self): - return 'typing_extensions.Concatenate' - - class _ConcatenateAliasBase(typing._FinalTypingBase, - metaclass=_ConcatenateAliasMeta, - _root=True): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("Concatenate cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Concatenate cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.Concatenate' - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateAliasBase(_root=True) # 3.10+ if hasattr(typing, 'TypeGuard'): @@ -1911,7 +1164,7 @@ def is_str(val: Union[str, float]): item = typing._type_check(parameters, f'{self} accepts only single type.') return typing._GenericAlias(self, (item,)) # 3.7-3.8 -elif sys.version_info[:2] >= (3, 7): +else: class _TypeGuardForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -1966,92 +1219,13 @@ def is_str(val: Union[str, float]): ``TypeGuard`` also works with type variables. For more information, see PEP 647 (User-Defined Type Guards). """) -# 3.6 -else: - class _TypeGuard(typing._FinalTypingBase, _root=True): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - f'{cls.__name__[1:]} accepts only a single type.'), - _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += f'[{typing._type_repr(self.__type__)}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - def __eq__(self, other): - if not isinstance(other, _TypeGuard): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - TypeGuard = _TypeGuard(_root=True) +# if hasattr(typing, "Self"): Self = typing.Self -elif sys.version_info[:2] >= (3, 7): +# 3.7+ +else: # Vendored from cpython typing._SpecialFrom class _SpecialForm(typing._Final, _root=True): __slots__ = ('_name', '__doc__', '_getitem') @@ -2111,35 +1285,13 @@ def parse(self, data: bytes) -> Self: """ raise TypeError(f"{self} is not subscriptable") -else: - class _Self(typing._FinalTypingBase, _root=True): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass().") - - Self = _Self(_root=True) +# if hasattr(typing, 'Required'): Required = typing.Required NotRequired = typing.NotRequired +# 3.9+ elif sys.version_info[:2] >= (3, 9): class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -2181,15 +1333,15 @@ class Movie(TypedDict): """ item = typing._type_check(parameters, f'{self._name} accepts only single type') return typing._GenericAlias(self, (item,)) - -elif sys.version_info[:2] >= (3, 7): +# 3.7-3.8 +else: class _RequiredForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name def __getitem__(self, parameters): item = typing._type_check(parameters, - '{} accepts only single type'.format(self._name)) + f'{self._name} accepts only single type') return typing._GenericAlias(self, (item,)) Required = _RequiredForm( @@ -2223,75 +1375,3 @@ class Movie(TypedDict): year=1999, ) """) -else: - # NOTE: Modeled after _Final's implementation when _FinalTypingBase available - class _MaybeRequired(typing._FinalTypingBase, _root=True): - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, type(self)): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - class _Required(_MaybeRequired, _root=True): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - - class _NotRequired(_MaybeRequired, _root=True): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - - Required = _Required(_root=True) - NotRequired = _NotRequired(_root=True) From a629d6802634a2fd9e30c1a319f7ef1016a6cc9c Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 11 Nov 2021 17:27:56 +0000 Subject: [PATCH 03/12] Inline various functions --- typing_extensions/src/typing_extensions.py | 107 +++++++++------------ 1 file changed, 48 insertions(+), 59 deletions(-) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index 286771cf..a9485248 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -5,19 +5,6 @@ import sys import typing - -# The function below is a copy of typing internal helpers. -# It is needed by _ProtocolMeta -def _check_generic(cls, parameters): - if not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - alen = len(parameters) - elen = len(cls.__parameters__) - if alen != elen: - raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};" - f" actual {alen}, expected {elen}") - - # Please keep __all__ alphabetized within each category. __all__ = [ # Super-special typing primitives. @@ -203,30 +190,6 @@ def __getitem__(self, parameters): 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'ContextManager', 'AsyncContextManager'] - -def _get_protocol_attrs(cls): - attrs = set() - for base in cls.__mro__[:-1]: # without object - if base.__name__ in ('Protocol', 'Generic'): - continue - annotations = getattr(base, '__annotations__', {}) - for attr in list(base.__dict__.keys()) + list(annotations.keys()): - if (not attr.startswith('_abc_') and attr not in ( - '__abstractmethods__', '__annotations__', '__weakref__', - '_is_protocol', '_is_runtime_protocol', '__dict__', - '__args__', '__slots__', - '__next_in_mro__', '__parameters__', '__origin__', - '__orig_bases__', '__extra__', '__tree_hash__', - '__doc__', '__subclasshook__', '__init__', '__new__', - '__module__', '_MutableMapping__marker', '_gorg')): - attrs.add(attr) - return attrs - - -def _is_callable_members_only(cls): - return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) - - # 3.8+ if hasattr(typing, 'Protocol'): Protocol = typing.Protocol @@ -234,6 +197,40 @@ def _is_callable_members_only(cls): else: from typing import _collect_type_vars # noqa + # The function below is a copy of an internal typing helper. + # It is needed by Protocol.__class_getitem__ + def _check_generic(cls, parameters): + if not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + alen = len(parameters) + elen = len(cls.__parameters__) + if alen != elen: + raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};" + f" actual {alen}, expected {elen}") + + def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in ('Protocol', 'Generic'): + continue + annotations = getattr(base, '__annotations__', {}) + for attr in list(base.__dict__.keys()) + list(annotations.keys()): + if (not attr.startswith('_abc_') and attr not in ( + '__abstractmethods__', '__annotations__', '__weakref__', + '_is_protocol', '_is_runtime_protocol', '__dict__', + '__args__', '__slots__', + '__next_in_mro__', '__parameters__', '__origin__', + '__orig_bases__', '__extra__', '__tree_hash__', + '__doc__', '__subclasshook__', '__init__', '__new__', + '__module__', '_MutableMapping__marker', '_gorg')): + attrs.add(attr) + return attrs + + def _is_callable_members_only(cls): + return all( + callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls) + ) + def _no_init(self, *args, **kwargs): if type(self)._is_protocol: raise TypeError('Protocols cannot be instantiated') @@ -763,15 +760,9 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): # 3.7-3.9 else: try: - # 3.9+ - from typing import _BaseGenericAlias - except ImportError: - _BaseGenericAlias = typing._GenericAlias - try: - # 3.9+ - from typing import GenericAlias + from typing import _BaseGenericAlias, GenericAlias # 3.9+ except ImportError: - GenericAlias = typing._GenericAlias + _BaseGenericAlias = GenericAlias = typing._GenericAlias # 3.7-3.8 def get_origin(tp): """Get the unsubscripted version of a type. @@ -1051,20 +1042,18 @@ def __parameters__(self): tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) ) - -# 3.7-3.9 -@typing._tp_cache -def _concatenate_getitem(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Concatenate of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if not isinstance(parameters[-1], ParamSpec): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = tuple(typing._type_check(p, msg) for p in parameters) - return _ConcatenateGenericAlias(self, parameters) + @typing._tp_cache + def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) # 3.10+ From ccda55bab202a0d6ad5552f88cebe32608039ff3 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 12 Nov 2021 00:14:48 +0000 Subject: [PATCH 04/12] Fix `__all__` ordering --- typing_extensions/src/typing_extensions.py | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index a9485248..a70d0c7a 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -8,51 +8,51 @@ # Please keep __all__ alphabetized within each category. __all__ = [ # Super-special typing primitives. + 'Annotated', 'ClassVar', 'Concatenate', 'Final', + 'Literal', 'ParamSpec', + 'Protocol', 'Self', 'Type', # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', + 'AsyncContextManager', + 'AsyncGenerator', 'AsyncIterable', + 'AsyncIterator', + 'Awaitable', + 'ContextManager', 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'ChainMap', + + # Structural checks, a.k.a. protocols. + 'SupportsIndex', # Concrete collection types. - 'ContextManager', + 'ChainMap', 'Counter', 'Deque', 'DefaultDict', 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsIndex', + 'TypedDict', # Not really a type. # One-off things. - 'Annotated', 'final', 'get_args', 'get_origin', 'get_type_hints', 'IntVar', - 'Literal', 'NewType', + 'NoReturn', 'overload', - 'Protocol', 'runtime', 'runtime_checkable', 'Text', 'TypeAlias', 'TypeGuard', 'TYPE_CHECKING', - 'NoReturn', ] NoReturn = typing.NoReturn From 2ea345ca7c79d5fa62c4e813752e06015ae1399f Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 28 Nov 2021 00:46:51 +0000 Subject: [PATCH 05/12] Add common _ReprForm --- typing_extensions/src/typing_extensions.py | 76 +++++++--------------- 1 file changed, 24 insertions(+), 52 deletions(-) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index a70d0c7a..ee84b53c 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -62,6 +62,12 @@ KT = typing.TypeVar('KT') # Key type. VT = typing.TypeVar('VT') # Value type. + +class _ReprForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + ClassVar = typing.ClassVar # On older versions of typing there is an internal class named "Final". @@ -70,11 +76,7 @@ Final = typing.Final # 3.7 else: - class _FinalForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - + class _FinalForm(_ReprForm, _root=True): def __getitem__(self, parameters): item = typing._type_check(parameters, f'{self._name} accepts only single type') @@ -132,11 +134,7 @@ def IntVar(name): Literal = typing.Literal # 3.7: else: - class _LiteralForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - + class _LiteralForm(_ReprForm, _root=True): def __getitem__(self, parameters): return typing._GenericAlias(self, parameters) @@ -816,11 +814,7 @@ def get_args(tp): TypeAlias = typing.TypeAlias # 3.9 elif sys.version_info[:2] >= (3, 9): - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeAliasForm + @_ReprForm def TypeAlias(self, parameters): """Special marker indicating that an assignment should be recognized as a proper type alias definition by type @@ -835,21 +829,17 @@ def TypeAlias(self, parameters): raise TypeError(f"{self} is not subscriptable") # 3.7-3.8 else: - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name + TypeAlias = _ReprForm('TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. - TypeAlias = _TypeAliasForm('TypeAlias', - doc="""Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. + For example:: - For example:: + Predicate: TypeAlias = Callable[..., bool] - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example - above.""") + It's invalid when used anywhere except as in the example + above.""") # Python 3.10+ has PEP 612 if hasattr(typing, 'ParamSpecArgs'): @@ -1062,7 +1052,7 @@ def _concatenate_getitem(self, parameters): _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa # 3.9 elif sys.version_info[:2] >= (3, 9): - @_TypeAliasForm + @_ReprForm def Concatenate(self, parameters): """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a higher order function which adds, removes or transforms parameters of a @@ -1077,10 +1067,7 @@ def Concatenate(self, parameters): return _concatenate_getitem(self, parameters) # 3.7-8 else: - class _ConcatenateForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - + class _ConcatenateForm(_ReprForm, _root=True): def __getitem__(self, parameters): return _concatenate_getitem(self, parameters) @@ -1102,11 +1089,7 @@ def __getitem__(self, parameters): TypeGuard = typing.TypeGuard # 3.9 elif sys.version_info[:2] >= (3, 9): - class _TypeGuardForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeGuardForm + @_ReprForm def TypeGuard(self, parameters): """Special typing form used to annotate the return type of a user-defined type guard function. ``TypeGuard`` only accepts a single type argument. @@ -1154,11 +1137,7 @@ def is_str(val: Union[str, float]): return typing._GenericAlias(self, (item,)) # 3.7-3.8 else: - class _TypeGuardForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - + class _TypeGuardForm(_ReprForm, _root=True): def __getitem__(self, parameters): item = typing._type_check(parameters, f'{self._name} accepts only a single type') @@ -1282,11 +1261,7 @@ def parse(self, data: bytes) -> Self: NotRequired = typing.NotRequired # 3.9+ elif sys.version_info[:2] >= (3, 9): - class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_ExtensionsSpecialForm + @_ReprForm def Required(self, parameters): """A special typing construct to mark a key of a total=False TypedDict as required. For example: @@ -1306,7 +1281,7 @@ class Movie(TypedDict, total=False): item = typing._type_check(parameters, f'{self._name} accepts only single type') return typing._GenericAlias(self, (item,)) - @_ExtensionsSpecialForm + @_ReprForm def NotRequired(self, parameters): """A special typing construct to mark a key of a TypedDict as potentially missing. For example: @@ -1324,10 +1299,7 @@ class Movie(TypedDict): return typing._GenericAlias(self, (item,)) # 3.7-3.8 else: - class _RequiredForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - + class _RequiredForm(_ReprForm, _root=True): def __getitem__(self, parameters): item = typing._type_check(parameters, f'{self._name} accepts only single type') From 5394de39ee70337ccbb0c5f2544c2f42ee000623 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 28 Nov 2021 01:05:31 +0000 Subject: [PATCH 06/12] Collate all unconditionally re-exported names --- typing_extensions/src/typing_extensions.py | 47 ++++++++++------------ 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index ee84b53c..d868319c 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -55,7 +55,28 @@ 'TYPE_CHECKING', ] +# Unconditionally re-exported names from typing +ClassVar = typing.ClassVar +Type = typing.Type # This is not a real generic class. Don't use outside annotations. + +NewType = typing.NewType NoReturn = typing.NoReturn +overload = typing.overload +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + +AsyncContextManager = typing.AsyncContextManager +AsyncGenerator = typing.AsyncGenerator +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Awaitable = typing.Awaitable +ContextManager = typing.ContextManager +Coroutine = typing.Coroutine + +ChainMap = typing.ChainMap +Counter = typing.Counter +Deque = typing.Deque +DefaultDict = typing.DefaultDict # Some unconstrained type variables. These are used by the container types. # (These are not for export.) @@ -68,8 +89,6 @@ def __repr__(self): return 'typing_extensions.' + self._name -ClassVar = typing.ClassVar - # On older versions of typing there is an internal class named "Final". # 3.8+ if hasattr(typing, 'Final'): @@ -152,22 +171,6 @@ def __getitem__(self, parameters): checking verifying that the parameter is actually a value instead of a type.""") -overload = typing.overload - -# This is not a real generic class. Don't use outside annotations. -Type = typing.Type - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator -Deque = typing.Deque -ContextManager = typing.ContextManager -AsyncContextManager = typing.AsyncContextManager -DefaultDict = typing.DefaultDict - # 3.7.2+ if hasattr(typing, 'OrderedDict'): OrderedDict = typing.OrderedDict @@ -175,14 +178,6 @@ def __getitem__(self, parameters): else: OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) -Counter = typing.Counter -ChainMap = typing.ChainMap -AsyncGenerator = typing.AsyncGenerator - -NewType = typing.NewType -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - _PROTO_WHITELIST = ['Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', From 9571f6270aa8c20d0670b750559c401d404b1e49 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 27 Nov 2021 23:51:47 +0000 Subject: [PATCH 07/12] Remove tests for unconditionally exported names --- .../src/test_typing_extensions.py | 439 +----------------- 1 file changed, 1 insertion(+), 438 deletions(-) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index a568e873..a52deabd 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -1,7 +1,6 @@ import sys import os import abc -import contextlib import collections import collections.abc import pickle @@ -48,89 +47,6 @@ class Employee: pass -class NoReturnTests(BaseTestCase): - - def test_noreturn_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, NoReturn) - - def test_noreturn_subclass_type_error_1(self): - with self.assertRaises(TypeError): - issubclass(Employee, NoReturn) - - def test_noreturn_subclass_type_error_2(self): - with self.assertRaises(TypeError): - issubclass(NoReturn, Employee) - - def test_repr(self): - if hasattr(typing, 'NoReturn'): - self.assertEqual(repr(NoReturn), 'typing.NoReturn') - else: - self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn') - - def test_not_generic(self): - with self.assertRaises(TypeError): - NoReturn[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(NoReturn): - pass - with self.assertRaises(TypeError): - class A(type(NoReturn)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - NoReturn() - with self.assertRaises(TypeError): - type(NoReturn)() - - -class ClassVarTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - ClassVar[1] - with self.assertRaises(TypeError): - ClassVar[int, str] - with self.assertRaises(TypeError): - ClassVar[int][str] - - def test_repr(self): - if hasattr(typing, 'ClassVar'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(ClassVar), mod_name + '.ClassVar') - cv = ClassVar[int] - self.assertEqual(repr(cv), mod_name + '.ClassVar[int]') - cv = ClassVar[Employee] - self.assertEqual(repr(cv), mod_name + f'.ClassVar[{__name__}.Employee]') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(ClassVar)): - pass - with self.assertRaises(TypeError): - class C(type(ClassVar[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - ClassVar() - with self.assertRaises(TypeError): - type(ClassVar)() - with self.assertRaises(TypeError): - type(ClassVar[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, ClassVar[int]) - with self.assertRaises(TypeError): - issubclass(int, ClassVar) - - class FinalTests(BaseTestCase): def test_basics(self): @@ -338,76 +254,6 @@ def test_no_multiple_subscripts(self): with self.assertRaises(TypeError): Literal[1][1] - -class OverloadTests(BaseTestCase): - - def test_overload_fails(self): - with self.assertRaises(RuntimeError): - - @overload - def blah(): - pass - - blah() - - def test_overload_succeeds(self): - @overload - def blah(): - pass - - def blah(): - pass - - blah() - - - -T_a = TypeVar('T_a') - -class AwaitableWrapper(Awaitable[T_a]): - - def __init__(self, value): - self.value = value - - def __await__(self) -> typing.Iterator[T_a]: - yield - return self.value - -class AsyncIteratorWrapper(AsyncIterator[T_a]): - - def __init__(self, value: Iterable[T_a]): - self.value = value - - def __aiter__(self) -> AsyncIterator[T_a]: - return self - - async def __anext__(self) -> T_a: - data = await self.value - if data: - return data - else: - raise StopAsyncIteration - -class ACM: - async def __aenter__(self) -> int: - return 42 - - async def __aexit__(self, etype, eval, tb): - return None - - - -class A: - y: float -class B(A): - x: ClassVar[Optional['B']] = None - y: int - b: int -class CSub(B): - z: ClassVar['CSub'] = B() -class G(Generic[T]): - lst: ClassVar[List[T]] = [] - class Loop: attr: Final['Loop'] @@ -415,31 +261,10 @@ class NoneAndForward: parent: 'NoneAndForward' meaning: None -class XRepr(NamedTuple): - x: int - y: int = 1 - - def __str__(self): - return f'{self.x} -> {self.y}' - - def __add__(self, other): - return 0 - @runtime class HasCallProtocol(Protocol): __call__: typing.Callable - -async def g_with(am: AsyncContextManager[int]): - x: int - async with am as x: - return x - -try: - g_with(ACM()).send(None) -except StopIteration as e: - assert e.args[0] == 42 - Label = TypedDict('Label', [('label', str)]) class Point2D(TypedDict): @@ -509,16 +334,6 @@ def meth(x: int): ... class Der(ABase): ... self.assertEqual(gth(ABase.meth), {'x': int}) - def test_get_type_hints_ClassVar(self): - self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__), - {'var': ClassVar[ann_module2.CV]}) - self.assertEqual(gth(B, globals()), - {'y': int, 'x': ClassVar[Optional[B]], 'b': int}) - self.assertEqual(gth(CSub, globals()), - {'z': ClassVar[CSub], 'y': int, 'b': int, - 'x': ClassVar[Optional[B]]}) - self.assertEqual(gth(G), {'lst': ClassVar[List[T]]}) - def test_final_forward_ref(self): self.assertEqual(gth(Loop, globals())['attr'], Final[Loop]) self.assertNotEqual(gth(Loop, globals())['attr'], Final[int]) @@ -598,90 +413,7 @@ class C(Generic[T]): pass (Concatenate[int, P], int)) -class CollectionsAbcTests(BaseTestCase): - - def test_isinstance_collections(self): - self.assertNotIsInstance(1, collections.abc.Mapping) - self.assertNotIsInstance(1, collections.abc.Iterable) - self.assertNotIsInstance(1, collections.abc.Container) - self.assertNotIsInstance(1, collections.abc.Sized) - with self.assertRaises(TypeError): - isinstance(collections.deque(), typing_extensions.Deque[int]) - with self.assertRaises(TypeError): - issubclass(collections.Counter, typing_extensions.Counter[str]) - - def test_awaitable(self): - ns = {} - exec( - "async def foo() -> typing_extensions.Awaitable[int]:\n" - " return await AwaitableWrapper(42)\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing_extensions.Awaitable) - self.assertNotIsInstance(foo, typing_extensions.Awaitable) - g.send(None) # Run foo() till completion, to avoid warning. - - def test_coroutine(self): - ns = {} - exec( - "async def foo():\n" - " return\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing_extensions.Coroutine) - with self.assertRaises(TypeError): - isinstance(g, typing_extensions.Coroutine[int]) - self.assertNotIsInstance(foo, typing_extensions.Coroutine) - try: - g.send(None) - except StopIteration: - pass - - def test_async_iterable(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing_extensions.AsyncIterable) - self.assertIsInstance(it, typing_extensions.AsyncIterable) - self.assertNotIsInstance(42, typing_extensions.AsyncIterable) - - def test_async_iterator(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing_extensions.AsyncIterator) - self.assertNotIsInstance(42, typing_extensions.AsyncIterator) - - def test_deque(self): - self.assertIsSubclass(collections.deque, typing_extensions.Deque) - class MyDeque(typing_extensions.Deque[int]): ... - self.assertIsInstance(MyDeque(), collections.deque) - - def test_counter(self): - self.assertIsSubclass(collections.Counter, typing_extensions.Counter) - - def test_defaultdict_instantiation(self): - self.assertIs( - type(typing_extensions.DefaultDict()), - collections.defaultdict) - self.assertIs( - type(typing_extensions.DefaultDict[KT, VT]()), - collections.defaultdict) - self.assertIs( - type(typing_extensions.DefaultDict[str, int]()), - collections.defaultdict) - - def test_defaultdict_subclass(self): - - class MyDefDict(typing_extensions.DefaultDict[str, int]): - pass - - dd = MyDefDict() - self.assertIsInstance(dd, MyDefDict) - - self.assertIsSubclass(MyDefDict, collections.defaultdict) - self.assertNotIsSubclass(collections.defaultdict, MyDefDict) - +class OrderedDictTests(BaseTestCase): def test_ordereddict_instantiation(self): self.assertIs( type(typing_extensions.OrderedDict()), @@ -704,175 +436,6 @@ class MyOrdDict(typing_extensions.OrderedDict[str, int]): self.assertIsSubclass(MyOrdDict, collections.OrderedDict) self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict) - def test_chainmap_instantiation(self): - self.assertIs(type(typing_extensions.ChainMap()), collections.ChainMap) - self.assertIs(type(typing_extensions.ChainMap[KT, VT]()), collections.ChainMap) - self.assertIs(type(typing_extensions.ChainMap[str, int]()), collections.ChainMap) - class CM(typing_extensions.ChainMap[KT, VT]): ... - self.assertIs(type(CM[int, str]()), CM) - - def test_chainmap_subclass(self): - - class MyChainMap(typing_extensions.ChainMap[str, int]): - pass - - cm = MyChainMap() - self.assertIsInstance(cm, MyChainMap) - - self.assertIsSubclass(MyChainMap, collections.ChainMap) - self.assertNotIsSubclass(collections.ChainMap, MyChainMap) - - def test_deque_instantiation(self): - self.assertIs(type(typing_extensions.Deque()), collections.deque) - self.assertIs(type(typing_extensions.Deque[T]()), collections.deque) - self.assertIs(type(typing_extensions.Deque[int]()), collections.deque) - class D(typing_extensions.Deque[T]): ... - self.assertIs(type(D[int]()), D) - - def test_counter_instantiation(self): - self.assertIs(type(typing_extensions.Counter()), collections.Counter) - self.assertIs(type(typing_extensions.Counter[T]()), collections.Counter) - self.assertIs(type(typing_extensions.Counter[int]()), collections.Counter) - class C(typing_extensions.Counter[T]): ... - self.assertIs(type(C[int]()), C) - self.assertEqual(C.__bases__, (collections.Counter, typing.Generic)) - - def test_counter_subclass_instantiation(self): - - class MyCounter(typing_extensions.Counter[int]): - pass - - d = MyCounter() - self.assertIsInstance(d, MyCounter) - self.assertIsInstance(d, collections.Counter) - self.assertIsInstance(d, typing_extensions.Counter) - - def test_async_generator(self): - ns = {} - exec("async def f():\n" - " yield 42\n", globals(), ns) - g = ns['f']() - self.assertIsSubclass(type(g), typing_extensions.AsyncGenerator) - - def test_no_async_generator_instantiation(self): - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator() - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator[T, T]() - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator[int, int]() - - def test_subclassing_async_generator(self): - class G(typing_extensions.AsyncGenerator[int, int]): - def asend(self, value): - pass - def athrow(self, typ, val=None, tb=None): - pass - - ns = {} - exec('async def g(): yield 0', globals(), ns) - g = ns['g'] - self.assertIsSubclass(G, typing_extensions.AsyncGenerator) - self.assertIsSubclass(G, typing_extensions.AsyncIterable) - self.assertIsSubclass(G, collections.abc.AsyncGenerator) - self.assertIsSubclass(G, collections.abc.AsyncIterable) - self.assertNotIsSubclass(type(g), G) - - instance = G() - self.assertIsInstance(instance, typing_extensions.AsyncGenerator) - self.assertIsInstance(instance, typing_extensions.AsyncIterable) - self.assertIsInstance(instance, collections.abc.AsyncGenerator) - self.assertIsInstance(instance, collections.abc.AsyncIterable) - self.assertNotIsInstance(type(g), G) - self.assertNotIsInstance(g, G) - - -class OtherABCTests(BaseTestCase): - - def test_contextmanager(self): - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertIsInstance(cm, typing_extensions.ContextManager) - self.assertNotIsInstance(42, typing_extensions.ContextManager) - - def test_async_contextmanager(self): - class NotACM: - pass - self.assertIsInstance(ACM(), typing_extensions.AsyncContextManager) - self.assertNotIsInstance(NotACM(), typing_extensions.AsyncContextManager) - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertNotIsInstance(cm, typing_extensions.AsyncContextManager) - self.assertEqual(typing_extensions.AsyncContextManager[int].__args__, (int,)) - with self.assertRaises(TypeError): - isinstance(42, typing_extensions.AsyncContextManager[int]) - with self.assertRaises(TypeError): - typing_extensions.AsyncContextManager[int, str] - - -class TypeTests(BaseTestCase): - - def test_type_basic(self): - - class User: pass - class BasicUser(User): pass - class ProUser(User): pass - - def new_user(user_class: Type[User]) -> User: - return user_class() - - new_user(BasicUser) - - def test_type_typevar(self): - - class User: pass - class BasicUser(User): pass - class ProUser(User): pass - - U = TypeVar('U', bound=User) - - def new_user(user_class: Type[U]) -> U: - return user_class() - - new_user(BasicUser) - - def test_type_optional(self): - A = Optional[Type[BaseException]] - - def foo(a: A) -> Optional[BaseException]: - if a is None: - return None - else: - return a() - - assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt) - assert foo(None) is None - - -class NewTypeTests(BaseTestCase): - - def test_basic(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - self.assertIsInstance(UserId(5), int) - self.assertIsInstance(UserName('Joe'), str) - self.assertEqual(UserId(5) + 1, 6) - - def test_errors(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - with self.assertRaises(TypeError): - issubclass(UserId, int) - with self.assertRaises(TypeError): - class D(UserName): - pass - class Coordinate(Protocol): x: int From 0dad6de60e2fbab6a49e9b9254d7f1f3ecf77e72 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 11 Nov 2021 17:03:55 +0000 Subject: [PATCH 08/12] Qualify uses of names from typing_extensions --- .../src/test_typing_extensions.py | 767 +++++++++--------- 1 file changed, 375 insertions(+), 392 deletions(-) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index a52deabd..06faa6f0 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -9,17 +9,8 @@ from unittest import TestCase, main, skipIf from test import ann_module, ann_module2, ann_module3 import typing -from typing import TypeVar, Optional, Union -from typing import T, KT, VT # Not in __all__. -from typing import Tuple, List, Dict, Iterable, Iterator, Callable -from typing import Generic, NamedTuple -from typing import no_type_check -import typing_extensions -from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self -from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard -from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired -from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload -from typing_extensions import get_type_hints +import typing_extensions as te +from typing_extensions import get_type_hints as gth # Flags used to mark tests that only apply after a specific # version of the typing module. @@ -51,223 +42,223 @@ class FinalTests(BaseTestCase): def test_basics(self): with self.assertRaises(TypeError): - Final[1] + te.Final[1] with self.assertRaises(TypeError): - Final[int, str] + te.Final[int, str] with self.assertRaises(TypeError): - Final[int][str] + te.Final[int][str] def test_repr(self): if hasattr(typing, 'Final'): mod_name = 'typing' else: mod_name = 'typing_extensions' - self.assertEqual(repr(Final), mod_name + '.Final') - cv = Final[int] + self.assertEqual(repr(te.Final), mod_name + '.Final') + cv = te.Final[int] self.assertEqual(repr(cv), mod_name + '.Final[int]') - cv = Final[Employee] + cv = te.Final[Employee] self.assertEqual(repr(cv), mod_name + f'.Final[{__name__}.Employee]') def test_cannot_subclass(self): with self.assertRaises(TypeError): - class C(type(Final)): + class C(type(te.Final)): pass with self.assertRaises(TypeError): - class C(type(Final[int])): + class C(type(te.Final[int])): pass def test_cannot_init(self): with self.assertRaises(TypeError): - Final() + te.Final() with self.assertRaises(TypeError): - type(Final)() + type(te.Final)() with self.assertRaises(TypeError): - type(Final[Optional[int]])() + type(te.Final[Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): - isinstance(1, Final[int]) + isinstance(1, te.Final[int]) with self.assertRaises(TypeError): - issubclass(int, Final) + issubclass(int, te.Final) class RequiredTests(BaseTestCase): def test_basics(self): with self.assertRaises(TypeError): - Required[1] + te.Required[1] with self.assertRaises(TypeError): - Required[int, str] + te.Required[int, str] with self.assertRaises(TypeError): - Required[int][str] + te.Required[int][str] def test_repr(self): if hasattr(typing, 'Required'): mod_name = 'typing' else: mod_name = 'typing_extensions' - self.assertEqual(repr(Required), mod_name + '.Required') - cv = Required[int] + self.assertEqual(repr(te.Required), mod_name + '.Required') + cv = te.Required[int] self.assertEqual(repr(cv), mod_name + '.Required[int]') - cv = Required[Employee] + cv = te.Required[Employee] self.assertEqual(repr(cv), mod_name + '.Required[%s.Employee]' % __name__) def test_cannot_subclass(self): with self.assertRaises(TypeError): - class C(type(Required)): + class C(type(te.Required)): pass with self.assertRaises(TypeError): - class C(type(Required[int])): + class C(type(te.Required[int])): pass def test_cannot_init(self): with self.assertRaises(TypeError): - Required() + te.Required() with self.assertRaises(TypeError): - type(Required)() + type(te.Required)() with self.assertRaises(TypeError): - type(Required[Optional[int]])() + type(te.Required[Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): - isinstance(1, Required[int]) + isinstance(1, te.Required[int]) with self.assertRaises(TypeError): - issubclass(int, Required) + issubclass(int, te.Required) class NotRequiredTests(BaseTestCase): def test_basics(self): with self.assertRaises(TypeError): - NotRequired[1] + te.NotRequired[1] with self.assertRaises(TypeError): - NotRequired[int, str] + te.NotRequired[int, str] with self.assertRaises(TypeError): - NotRequired[int][str] + te.NotRequired[int][str] def test_repr(self): if hasattr(typing, 'NotRequired'): mod_name = 'typing' else: mod_name = 'typing_extensions' - self.assertEqual(repr(NotRequired), mod_name + '.NotRequired') - cv = NotRequired[int] + self.assertEqual(repr(te.NotRequired), mod_name + '.NotRequired') + cv = te.NotRequired[int] self.assertEqual(repr(cv), mod_name + '.NotRequired[int]') - cv = NotRequired[Employee] + cv = te.NotRequired[Employee] self.assertEqual(repr(cv), mod_name + '.NotRequired[%s.Employee]' % __name__) def test_cannot_subclass(self): with self.assertRaises(TypeError): - class C(type(NotRequired)): + class C(type(te.NotRequired)): pass with self.assertRaises(TypeError): - class C(type(NotRequired[int])): + class C(type(te.NotRequired[int])): pass def test_cannot_init(self): with self.assertRaises(TypeError): - NotRequired() + te.NotRequired() with self.assertRaises(TypeError): - type(NotRequired)() + type(te.NotRequired)() with self.assertRaises(TypeError): - type(NotRequired[Optional[int]])() + type(te.NotRequired[Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): - isinstance(1, NotRequired[int]) + isinstance(1, te.NotRequired[int]) with self.assertRaises(TypeError): - issubclass(int, NotRequired) + issubclass(int, te.NotRequired) class IntVarTests(BaseTestCase): def test_valid(self): - T_ints = IntVar("T_ints") # noqa + T_ints = te.IntVar("T_ints") # noqa def test_invalid(self): with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", int) + T_ints = te.IntVar("T_ints", int) with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", bound=int) + T_ints = te.IntVar("T_ints", bound=int) with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", covariant=True) # noqa + T_ints = te.IntVar("T_ints", covariant=True) # noqa class LiteralTests(BaseTestCase): def test_basics(self): - Literal[1] - Literal[1, 2, 3] - Literal["x", "y", "z"] - Literal[None] + te.Literal[1] + te.Literal[1, 2, 3] + te.Literal["x", "y", "z"] + te.Literal[None] def test_illegal_parameters_do_not_raise_runtime_errors(self): # Type checkers should reject these types, but we do not # raise errors at runtime to maintain maximum flexibility - Literal[int] - Literal[Literal[1, 2], Literal[4, 5]] - Literal[3j + 2, ..., ()] - Literal[b"foo", u"bar"] - Literal[{"foo": 3, "bar": 4}] - Literal[T] + te.Literal[int] + te.Literal[te.Literal[1, 2], te.Literal[4, 5]] + te.Literal[3j + 2, ..., ()] + te.Literal[b"foo", u"bar"] + te.Literal[{"foo": 3, "bar": 4}] + te.Literal[T] def test_literals_inside_other_types(self): - List[Literal[1, 2, 3]] - List[Literal[("foo", "bar", "baz")]] + List[te.Literal[1, 2, 3]] + List[te.Literal[("foo", "bar", "baz")]] def test_repr(self): if hasattr(typing, 'Literal'): mod_name = 'typing' else: mod_name = 'typing_extensions' - self.assertEqual(repr(Literal[1]), mod_name + ".Literal[1]") - self.assertEqual(repr(Literal[1, True, "foo"]), mod_name + ".Literal[1, True, 'foo']") - self.assertEqual(repr(Literal[int]), mod_name + ".Literal[int]") - self.assertEqual(repr(Literal), mod_name + ".Literal") - self.assertEqual(repr(Literal[None]), mod_name + ".Literal[None]") + self.assertEqual(repr(te.Literal[1]), mod_name + ".Literal[1]") + self.assertEqual(repr(te.Literal[1, True, "foo"]), mod_name + ".Literal[1, True, 'foo']") + self.assertEqual(repr(te.Literal[int]), mod_name + ".Literal[int]") + self.assertEqual(repr(te.Literal), mod_name + ".Literal") + self.assertEqual(repr(te.Literal[None]), mod_name + ".Literal[None]") def test_cannot_init(self): with self.assertRaises(TypeError): - Literal() + te.Literal() with self.assertRaises(TypeError): - Literal[1]() + te.Literal[1]() with self.assertRaises(TypeError): - type(Literal)() + type(te.Literal)() with self.assertRaises(TypeError): - type(Literal[1])() + type(te.Literal[1])() def test_no_isinstance_or_issubclass(self): with self.assertRaises(TypeError): - isinstance(1, Literal[1]) + isinstance(1, te.Literal[1]) with self.assertRaises(TypeError): - isinstance(int, Literal[1]) + isinstance(int, te.Literal[1]) with self.assertRaises(TypeError): - issubclass(1, Literal[1]) + issubclass(1, te.Literal[1]) with self.assertRaises(TypeError): - issubclass(int, Literal[1]) + issubclass(int, te.Literal[1]) def test_no_subclassing(self): with self.assertRaises(TypeError): - class Foo(Literal[1]): pass + class Foo(te.Literal[1]): pass with self.assertRaises(TypeError): - class Bar(Literal): pass + class Bar(te.Literal): pass def test_no_multiple_subscripts(self): with self.assertRaises(TypeError): - Literal[1][1] + te.Literal[1][1] class Loop: - attr: Final['Loop'] + attr: te.Final['Loop'] class NoneAndForward: parent: 'NoneAndForward' meaning: None -@runtime -class HasCallProtocol(Protocol): +@te.runtime_checkable +class HasCallProtocol(te.Protocol): __call__: typing.Callable -Label = TypedDict('Label', [('label', str)]) +Label = te.TypedDict('Label', [('label', str)]) -class Point2D(TypedDict): +class Point2D(te.TypedDict): x: int y: int @@ -276,11 +267,11 @@ class Point2Dor3D(Point2D, total=False): class LabelPoint2D(Point2D, Label): ... -class Options(TypedDict, total=False): +class Options(te.TypedDict, total=False): log_level: int log_path: str -class BaseAnimal(TypedDict): +class BaseAnimal(te.TypedDict): name: str class Animal(BaseAnimal, total=False): @@ -291,9 +282,6 @@ class Cat(Animal): fur_color: str -gth = get_type_hints - - class GetTypeHintTests(BaseTestCase): def test_get_type_hints_modules(self): ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} @@ -335,99 +323,95 @@ class Der(ABase): ... self.assertEqual(gth(ABase.meth), {'x': int}) def test_final_forward_ref(self): - self.assertEqual(gth(Loop, globals())['attr'], Final[Loop]) - self.assertNotEqual(gth(Loop, globals())['attr'], Final[int]) - self.assertNotEqual(gth(Loop, globals())['attr'], Final) + self.assertEqual(gth(Loop, globals())['attr'], te.Final[Loop]) + self.assertNotEqual(gth(Loop, globals())['attr'], te.Final[int]) + self.assertNotEqual(gth(Loop, globals())['attr'], te.Final) class GetUtilitiesTestCase(TestCase): def test_get_origin(self): - from typing_extensions import get_origin - T = TypeVar('T') - P = ParamSpec('P') + P = te.ParamSpec('P') class C(Generic[T]): pass - self.assertIs(get_origin(C[int]), C) - self.assertIs(get_origin(C[T]), C) - self.assertIs(get_origin(int), None) - self.assertIs(get_origin(ClassVar[int]), ClassVar) - self.assertIs(get_origin(Union[int, str]), Union) - self.assertIs(get_origin(Literal[42, 43]), Literal) - self.assertIs(get_origin(Final[List[int]]), Final) - self.assertIs(get_origin(Generic), Generic) - self.assertIs(get_origin(Generic[T]), Generic) - self.assertIs(get_origin(List[Tuple[T, T]][int]), list) - self.assertIs(get_origin(Annotated[T, 'thing']), Annotated) - self.assertIs(get_origin(List), list) - self.assertIs(get_origin(Tuple), tuple) - self.assertIs(get_origin(Callable), collections.abc.Callable) + self.assertIs(te.get_origin(C[int]), C) + self.assertIs(te.get_origin(C[T]), C) + self.assertIs(te.get_origin(int), None) + self.assertIs(te.get_origin(ClassVar[int]), ClassVar) + self.assertIs(te.get_origin(Union[int, str]), Union) + self.assertIs(te.get_origin(te.Literal[42, 43]), te.Literal) + self.assertIs(te.get_origin(te.Final[List[int]]), te.Final) + self.assertIs(te.get_origin(Generic), Generic) + self.assertIs(te.get_origin(Generic[T]), Generic) + self.assertIs(te.get_origin(List[Tuple[T, T]][int]), list) + self.assertIs(te.get_origin(te.Annotated[T, 'thing']), te.Annotated) + self.assertIs(te.get_origin(List), list) + self.assertIs(te.get_origin(Tuple), tuple) + self.assertIs(te.get_origin(Callable), collections.abc.Callable) if sys.version_info >= (3, 9): - self.assertIs(get_origin(list[int]), list) - self.assertIs(get_origin(list), None) - self.assertIs(get_origin(P.args), P) - self.assertIs(get_origin(P.kwargs), P) + self.assertIs(te.get_origin(list[int]), list) + self.assertIs(te.get_origin(list), None) + self.assertIs(te.get_origin(P.args), P) + self.assertIs(te.get_origin(P.kwargs), P) def test_get_args(self): - from typing_extensions import get_args - T = TypeVar('T') class C(Generic[T]): pass - self.assertEqual(get_args(C[int]), (int,)) - self.assertEqual(get_args(C[T]), (T,)) - self.assertEqual(get_args(int), ()) - self.assertEqual(get_args(ClassVar[int]), (int,)) - self.assertEqual(get_args(Union[int, str]), (int, str)) - self.assertEqual(get_args(Literal[42, 43]), (42, 43)) - self.assertEqual(get_args(Final[List[int]]), (List[int],)) - self.assertEqual(get_args(Union[int, Tuple[T, int]][str]), + self.assertEqual(te.get_args(C[int]), (int,)) + self.assertEqual(te.get_args(C[T]), (T,)) + self.assertEqual(te.get_args(int), ()) + self.assertEqual(te.get_args(ClassVar[int]), (int,)) + self.assertEqual(te.get_args(Union[int, str]), (int, str)) + self.assertEqual(te.get_args(te.Literal[42, 43]), (42, 43)) + self.assertEqual(te.get_args(te.Final[List[int]]), (List[int],)) + self.assertEqual(te.get_args(Union[int, Tuple[T, int]][str]), (int, Tuple[str, int])) - self.assertEqual(get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]), + self.assertEqual(te.get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]), (int, Tuple[Optional[int], Optional[int]])) - self.assertEqual(get_args(Callable[[], T][int]), ([], int)) - self.assertEqual(get_args(Callable[..., int]), (..., int)) - self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]), + self.assertEqual(te.get_args(Callable[[], T][int]), ([], int)) + self.assertEqual(te.get_args(Callable[..., int]), (..., int)) + self.assertEqual(te.get_args(Union[int, Callable[[Tuple[T, ...]], str]]), (int, Callable[[Tuple[T, ...]], str])) - self.assertEqual(get_args(Tuple[int, ...]), (int, ...)) - self.assertEqual(get_args(Tuple[()]), ((),)) - self.assertEqual(get_args(Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three'])) - self.assertEqual(get_args(List), ()) - self.assertEqual(get_args(Tuple), ()) - self.assertEqual(get_args(Callable), ()) + self.assertEqual(te.get_args(Tuple[int, ...]), (int, ...)) + self.assertEqual(te.get_args(Tuple[()]), ((),)) + self.assertEqual(te.get_args(te.Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three'])) + self.assertEqual(te.get_args(List), ()) + self.assertEqual(te.get_args(Tuple), ()) + self.assertEqual(te.get_args(Callable), ()) if sys.version_info >= (3, 9): - self.assertEqual(get_args(list[int]), (int,)) - self.assertEqual(get_args(list), ()) + self.assertEqual(te.get_args(list[int]), (int,)) + self.assertEqual(te.get_args(list), ()) if sys.version_info >= (3, 9): # Support Python versions with and without the fix for # https://bugs.python.org/issue42195 # The first variant is for 3.9.2+, the second for 3.9.0 and 1 - self.assertIn(get_args(collections.abc.Callable[[int], str]), + self.assertIn(te.get_args(collections.abc.Callable[[int], str]), (([int], str), ([[int]], str))) - self.assertIn(get_args(collections.abc.Callable[[], str]), + self.assertIn(te.get_args(collections.abc.Callable[[], str]), (([], str), ([[]], str))) - self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str)) - P = ParamSpec('P') + self.assertEqual(te.get_args(collections.abc.Callable[..., str]), (..., str)) + P = te.ParamSpec('P') # In 3.9 and lower we use typing_extensions's hacky implementation # of ParamSpec, which gets incorrectly wrapped in a list - self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)]) - self.assertEqual(get_args(Callable[Concatenate[int, P], int]), - (Concatenate[int, P], int)) + self.assertIn(te.get_args(Callable[P, int]), [(P, int), ([P], int)]) + self.assertEqual(te.get_args(Callable[te.Concatenate[int, P], int]), + (te.Concatenate[int, P], int)) class OrderedDictTests(BaseTestCase): def test_ordereddict_instantiation(self): self.assertIs( - type(typing_extensions.OrderedDict()), + type(te.OrderedDict()), collections.OrderedDict) self.assertIs( - type(typing_extensions.OrderedDict[KT, VT]()), + type(te.OrderedDict[KT, VT]()), collections.OrderedDict) self.assertIs( - type(typing_extensions.OrderedDict[str, int]()), + type(te.OrderedDict[str, int]()), collections.OrderedDict) def test_ordereddict_subclass(self): - class MyOrdDict(typing_extensions.OrderedDict[str, int]): + class MyOrdDict(te.OrderedDict[str, int]): pass od = MyOrdDict() @@ -437,12 +421,12 @@ class MyOrdDict(typing_extensions.OrderedDict[str, int]): self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict) -class Coordinate(Protocol): +class Coordinate(te.Protocol): x: int y: int -@runtime -class Point(Coordinate, Protocol): +@te.runtime_checkable +class Point(Coordinate, te.Protocol): label: str class MyPoint: @@ -450,18 +434,18 @@ class MyPoint: y: int label: str -class XAxis(Protocol): +class XAxis(te.Protocol): x: int -class YAxis(Protocol): +class YAxis(te.Protocol): y: int -@runtime -class Position(XAxis, YAxis, Protocol): +@te.runtime_checkable +class Position(XAxis, YAxis, te.Protocol): pass -@runtime -class Proto(Protocol): +@te.runtime_checkable +class Proto(te.Protocol): attr: int def meth(self, arg: str) -> int: @@ -486,8 +470,8 @@ class NT(NamedTuple): class ProtocolTests(BaseTestCase): def test_basic_protocol(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): def meth(self): pass class C: pass @@ -504,8 +488,8 @@ def f(): self.assertNotIsInstance(f, P) def test_everything_implements_empty_protocol(self): - @runtime - class Empty(Protocol): pass + @te.runtime_checkable + class Empty(te.Protocol): pass class C: pass def f(): pass @@ -521,15 +505,15 @@ def f(): def test_no_inheritance_from_nominal(self): class C: pass - class BP(Protocol): pass + class BP(te.Protocol): pass with self.assertRaises(TypeError): - class P(C, Protocol): + class P(C, te.Protocol): pass with self.assertRaises(TypeError): - class P(Protocol, C): + class P(te.Protocol, C): pass with self.assertRaises(TypeError): - class P(BP, C, Protocol): + class P(BP, C, te.Protocol): pass class D(BP, C): pass class E(C, BP): pass @@ -537,13 +521,13 @@ class E(C, BP): pass self.assertNotIsInstance(E(), D) def test_no_instantiation(self): - class P(Protocol): pass + class P(te.Protocol): pass with self.assertRaises(TypeError): P() class C(P): pass self.assertIsInstance(C(), C) T = TypeVar('T') - class PG(Protocol[T]): pass + class PG(te.Protocol[T]): pass with self.assertRaises(TypeError): PG() with self.assertRaises(TypeError): @@ -554,8 +538,8 @@ class CG(PG[T]): pass self.assertIsInstance(CG[int](), CG) def test_cannot_instantiate_abstract(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): @abc.abstractmethod def ameth(self) -> int: raise NotImplementedError @@ -569,11 +553,11 @@ def ameth(self) -> int: self.assertIsInstance(C(), P) def test_subprotocols_extending(self): - class P1(Protocol): + class P1(te.Protocol): def meth1(self): pass - @runtime - class P2(P1, Protocol): + @te.runtime_checkable + class P2(P1, te.Protocol): def meth2(self): pass class C: @@ -595,14 +579,14 @@ def meth2(self): self.assertIsSubclass(C, P2) def test_subprotocols_merging(self): - class P1(Protocol): + class P1(te.Protocol): def meth1(self): pass - class P2(Protocol): + class P2(te.Protocol): def meth2(self): pass - @runtime - class P(P1, P2, Protocol): + @te.runtime_checkable + class P(P1, P2, te.Protocol): pass class C: def meth1(self): @@ -624,15 +608,15 @@ def meth2(self): def test_protocols_issubclass(self): T = TypeVar('T') - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): def x(self): ... - @runtime - class PG(Protocol[T]): + @te.runtime_checkable + class PG(te.Protocol[T]): def x(self): ... - class BadP(Protocol): + class BadP(te.Protocol): def x(self): ... - class BadPG(Protocol[T]): + class BadPG(te.Protocol[T]): def x(self): ... class C: def x(self): ... @@ -655,8 +639,8 @@ def x(self): ... def test_protocols_issubclass_non_callable(self): class C: x = 1 - @runtime - class PNonCall(Protocol): + @te.runtime_checkable + class PNonCall(te.Protocol): x = 1 with self.assertRaises(TypeError): issubclass(C, PNonCall) @@ -677,15 +661,15 @@ class D(PNonCall): ... def test_protocols_isinstance(self): T = TypeVar('T') - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): def meth(x): ... - @runtime - class PG(Protocol[T]): + @te.runtime_checkable + class PG(te.Protocol[T]): def meth(x): ... - class BadP(Protocol): + class BadP(te.Protocol): def meth(x): ... - class BadPG(Protocol[T]): + class BadPG(te.Protocol[T]): def meth(x): ... class C: def meth(x): ... @@ -733,11 +717,11 @@ class Bad: pass def test_protocols_isinstance_init(self): T = TypeVar('T') - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): x = 1 - @runtime - class PG(Protocol[T]): + @te.runtime_checkable + class PG(te.Protocol[T]): x = 1 class C: def __init__(self, x): @@ -746,10 +730,10 @@ def __init__(self, x): self.assertIsInstance(C(1), PG) def test_protocols_support_register(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): x = 1 - class PM(Protocol): + class PM(te.Protocol): def meth(self): pass class D(PM): pass class C: pass @@ -759,8 +743,8 @@ class C: pass self.assertIsInstance(C(), D) def test_none_on_non_callable_doesnt_block_implementation(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): x = 1 class A: x = 1 @@ -773,8 +757,8 @@ def __init__(self): self.assertIsInstance(C(), P) def test_none_on_callable_blocks_implementation(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): def x(self): ... class A: def x(self): ... @@ -787,10 +771,10 @@ def __init__(self): self.assertNotIsInstance(C(), P) def test_non_protocol_subclasses(self): - class P(Protocol): + class P(te.Protocol): x = 1 - @runtime - class PR(Protocol): + @te.runtime_checkable + class PR(te.Protocol): def meth(self): pass class NonP(P): x = 1 @@ -807,7 +791,7 @@ def meth(self): pass self.assertIsSubclass(NonPR, PR) def test_custom_subclasshook(self): - class P(Protocol): + class P(te.Protocol): x = 1 class OKClass: pass class BadClass: @@ -822,8 +806,8 @@ def __subclasshook__(cls, other): self.assertNotIsSubclass(BadClass, C) def test_issubclass_fails_correctly(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): x = 1 class C: pass with self.assertRaises(TypeError): @@ -832,10 +816,10 @@ class C: pass def test_defining_generic_protocols_old_style(self): T = TypeVar('T') S = TypeVar('S') - @runtime - class PR(Protocol, Generic[T, S]): + @te.runtime_checkable + class PR(te.Protocol, Generic[T, S]): def meth(self): pass - class P(PR[int, str], Protocol): + class P(PR[int, str], te.Protocol): y = 1 with self.assertRaises(TypeError): self.assertIsSubclass(PR[int, str], PR) @@ -845,12 +829,12 @@ class P(PR[int, str], Protocol): if not TYPING_3_10_0: with self.assertRaises(TypeError): PR[int, 1] - class P1(Protocol, Generic[T]): + class P1(te.Protocol, Generic[T]): def bar(self, x: T) -> str: ... - class P2(Generic[T], Protocol): + class P2(Generic[T], te.Protocol): def bar(self, x: T) -> str: ... - @runtime - class PSub(P1[str], Protocol): + @te.runtime_checkable + class PSub(P1[str], te.Protocol): x = 1 class Test: x = 1 @@ -863,7 +847,7 @@ def bar(self, x: str) -> str: def test_init_called(self): T = TypeVar('T') - class P(Protocol[T]): pass + class P(te.Protocol[T]): pass class C(P[T]): def __init__(self): self.test = 'OK' @@ -873,39 +857,39 @@ def test_protocols_bad_subscripts(self): T = TypeVar('T') S = TypeVar('S') with self.assertRaises(TypeError): - class P(Protocol[T, T]): pass + class P(te.Protocol[T, T]): pass with self.assertRaises(TypeError): - class P(Protocol[int]): pass + class P(te.Protocol[int]): pass with self.assertRaises(TypeError): - class P(Protocol[T], Protocol[S]): pass + class P(te.Protocol[T], te.Protocol[S]): pass with self.assertRaises(TypeError): - class P(typing.Mapping[T, S], Protocol[T]): pass + class P(typing.Mapping[T, S], te.Protocol[T]): pass def test_generic_protocols_repr(self): T = TypeVar('T') S = TypeVar('S') - class P(Protocol[T, S]): pass + class P(te.Protocol[T, S]): pass self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) def test_generic_protocols_eq(self): T = TypeVar('T') S = TypeVar('S') - class P(Protocol[T, S]): pass + class P(te.Protocol[T, S]): pass self.assertEqual(P, P) self.assertEqual(P[int, T], P[int, T]) self.assertEqual(P[T, T][Tuple[T, S]][int, str], P[Tuple[int, str], Tuple[int, str]]) def test_generic_protocols_special_from_protocol(self): - @runtime - class PR(Protocol): + @te.runtime_checkable + class PR(te.Protocol): x = 1 - class P(Protocol): + class P(te.Protocol): def meth(self): pass T = TypeVar('T') - class PG(Protocol[T]): + class PG(te.Protocol[T]): x = 1 def meth(self): pass @@ -926,18 +910,18 @@ def meth(self): def test_no_runtime_deco_on_nominal(self): with self.assertRaises(TypeError): - @runtime + @te.runtime_checkable class C: pass - class Proto(Protocol): + class Proto(te.Protocol): x = 1 with self.assertRaises(TypeError): - @runtime + @te.runtime_checkable class Concrete(Proto): pass def test_none_treated_correctly(self): - @runtime - class P(Protocol): + @te.runtime_checkable + class P(te.Protocol): x = None # type: int class B(object): pass self.assertNotIsInstance(B(), P) @@ -957,7 +941,7 @@ def __init__(self): self.assertIsInstance(D(), P) def test_protocols_in_unions(self): - class P(Protocol): + class P(te.Protocol): x = None # type: int Alias = typing.Union[typing.Iterable, P] Alias2 = typing.Union[P, typing.Iterable] @@ -967,8 +951,8 @@ def test_protocols_pickleable(self): global P, CP # pickle wants to reference the class by name T = TypeVar('T') - @runtime - class P(Protocol[T]): + @te.runtime_checkable + class P(te.Protocol[T]): x = 1 class CP(P[int]): pass @@ -990,8 +974,8 @@ class E: self.assertIsInstance(E(), D) def test_collections_protocols_allowed(self): - @runtime_checkable - class Custom(collections.abc.Iterable, Protocol): + @te.runtime_checkable + class Custom(collections.abc.Iterable, te.Protocol): def close(self): pass class A: ... @@ -1005,10 +989,10 @@ def close(self): self.assertNotIsSubclass(A, Custom) def test_no_init_same_for_different_protocol_implementations(self): - class CustomProtocolWithoutInitA(Protocol): + class CustomProtocolWithoutInitA(te.Protocol): pass - class CustomProtocolWithoutInitB(Protocol): + class CustomProtocolWithoutInitB(te.Protocol): pass self.assertEqual(CustomProtocolWithoutInitA.__init__, CustomProtocolWithoutInitB.__init__) @@ -1017,7 +1001,7 @@ class CustomProtocolWithoutInitB(Protocol): class TypedDictTests(BaseTestCase): def test_basics_iterable_syntax(self): - Emp = TypedDict('Emp', {'name': str, 'id': int}) + Emp = te.TypedDict('Emp', {'name': str, 'id': int}) self.assertIsSubclass(Emp, dict) self.assertIsSubclass(Emp, typing.MutableMapping) self.assertNotIsSubclass(Emp, collections.abc.Sequence) @@ -1032,7 +1016,7 @@ def test_basics_iterable_syntax(self): self.assertEqual(Emp.__total__, True) def test_basics_keywords_syntax(self): - Emp = TypedDict('Emp', name=str, id=int) + Emp = te.TypedDict('Emp', name=str, id=int) self.assertIsSubclass(Emp, dict) self.assertIsSubclass(Emp, typing.MutableMapping) self.assertNotIsSubclass(Emp, collections.abc.Sequence) @@ -1047,8 +1031,8 @@ def test_basics_keywords_syntax(self): self.assertEqual(Emp.__total__, True) def test_typeddict_special_keyword_names(self): - TD = TypedDict("TD", cls=type, self=object, typename=str, _typename=int, - fields=list, _fields=dict) + TD = te.TypedDict("TD", cls=type, self=object, typename=str, _typename=int, + fields=list, _fields=dict) self.assertEqual(TD.__name__, 'TD') self.assertEqual(TD.__annotations__, {'cls': type, 'self': object, 'typename': str, '_typename': int, 'fields': list, '_fields': dict}) @@ -1064,28 +1048,28 @@ def test_typeddict_special_keyword_names(self): @skipIf(hasattr(typing, 'TypedDict'), "Should be tested by upstream") def test_typeddict_create_errors(self): with self.assertRaises(TypeError): - TypedDict.__new__() + te.TypedDict.__new__() with self.assertRaises(TypeError): - TypedDict() + te.TypedDict() with self.assertRaises(TypeError): - TypedDict('Emp', [('name', str)], None) + te.TypedDict('Emp', [('name', str)], None) with self.assertWarns(DeprecationWarning): - Emp = TypedDict(_typename='Emp', name=str, id=int) + Emp = te.TypedDict(_typename='Emp', name=str, id=int) self.assertEqual(Emp.__name__, 'Emp') self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) with self.assertWarns(DeprecationWarning): - Emp = TypedDict('Emp', _fields={'name': str, 'id': int}) + Emp = te.TypedDict('Emp', _fields={'name': str, 'id': int}) self.assertEqual(Emp.__name__, 'Emp') self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) def test_typeddict_errors(self): - Emp = TypedDict('Emp', {'name': str, 'id': int}) + Emp = te.TypedDict('Emp', {'name': str, 'id': int}) if sys.version_info >= (3, 9, 2): - self.assertEqual(TypedDict.__module__, 'typing') + self.assertEqual(te.TypedDict.__module__, 'typing') else: - self.assertEqual(TypedDict.__module__, 'typing_extensions') + self.assertEqual(te.TypedDict.__module__, 'typing_extensions') jim = Emp(name='Jim', id=1) with self.assertRaises(TypeError): isinstance({}, Emp) @@ -1094,16 +1078,16 @@ def test_typeddict_errors(self): with self.assertRaises(TypeError): issubclass(dict, Emp) with self.assertRaises(TypeError): - TypedDict('Hi', x=1) + te.TypedDict('Hi', x=1) with self.assertRaises(TypeError): - TypedDict('Hi', [('x', int), ('y', 1)]) + te.TypedDict('Hi', [('x', int), ('y', 1)]) with self.assertRaises(TypeError): - TypedDict('Hi', [('x', int)], y=int) + te.TypedDict('Hi', [('x', int)], y=int) def test_py36_class_syntax_usage(self): self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D') self.assertEqual(LabelPoint2D.__module__, __name__) - self.assertEqual(get_type_hints(LabelPoint2D), {'x': int, 'y': int, 'label': str}) + self.assertEqual(gth(LabelPoint2D), {'x': int, 'y': int, 'label': str}) self.assertEqual(LabelPoint2D.__bases__, (dict,)) self.assertEqual(LabelPoint2D.__total__, True) self.assertNotIsSubclass(LabelPoint2D, typing.Sequence) @@ -1115,7 +1099,7 @@ def test_py36_class_syntax_usage(self): def test_pickle(self): global EmpD # pickle wants to reference the class by name - EmpD = TypedDict('EmpD', name=str, id=int) + EmpD = te.TypedDict('EmpD', name=str, id=int) jane = EmpD({'name': 'jane', 'id': 37}) for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(jane, proto) @@ -1127,13 +1111,13 @@ def test_pickle(self): self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane) def test_optional(self): - EmpD = TypedDict('EmpD', name=str, id=int) + EmpD = te.TypedDict('EmpD', name=str, id=int) self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD]) self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD]) def test_total(self): - D = TypedDict('D', {'x': int}, total=False) + D = te.TypedDict('D', {'x': int}, total=False) self.assertEqual(D(), {}) self.assertEqual(D(x=1), {'x': 1}) self.assertEqual(D.__total__, False) @@ -1153,11 +1137,11 @@ def test_optional_keys(self): def test_keys_inheritance(self): assert BaseAnimal.__required_keys__ == frozenset(['name']) assert BaseAnimal.__optional_keys__ == frozenset([]) - assert get_type_hints(BaseAnimal) == {'name': str} + assert gth(BaseAnimal) == {'name': str} assert Animal.__required_keys__ == frozenset(['name']) assert Animal.__optional_keys__ == frozenset(['tail', 'voice']) - assert get_type_hints(Animal) == { + assert gth(Animal) == { 'name': str, 'tail': bool, 'voice': str, @@ -1165,7 +1149,7 @@ def test_keys_inheritance(self): assert Cat.__required_keys__ == frozenset(['name', 'fur_color']) assert Cat.__optional_keys__ == frozenset(['tail', 'voice']) - assert get_type_hints(Cat) == { + assert gth(Cat) == { 'fur_color': str, 'name': str, 'tail': bool, @@ -1181,24 +1165,24 @@ def test_repr(self): else: mod_name = "typing_extensions" self.assertEqual( - repr(Annotated[int, 4, 5]), + repr(te.Annotated[int, 4, 5]), mod_name + ".Annotated[int, 4, 5]" ) self.assertEqual( - repr(Annotated[List[int], 4, 5]), + repr(te.Annotated[List[int], 4, 5]), mod_name + ".Annotated[typing.List[int], 4, 5]" ) def test_flatten(self): - A = Annotated[Annotated[int, 4], 5] - self.assertEqual(A, Annotated[int, 4, 5]) + A = te.Annotated[te.Annotated[int, 4], 5] + self.assertEqual(A, te.Annotated[int, 4, 5]) self.assertEqual(A.__metadata__, (4, 5)) self.assertEqual(A.__origin__, int) def test_specialize(self): - L = Annotated[List[T], "my decoration"] - LI = Annotated[List[int], "my decoration"] - self.assertEqual(L[int], Annotated[List[int], "my decoration"]) + L = te.Annotated[List[T], "my decoration"] + LI = te.Annotated[List[int], "my decoration"] + self.assertEqual(L[int], te.Annotated[List[int], "my decoration"]) self.assertEqual(L[int].__metadata__, ("my decoration",)) self.assertEqual(L[int].__origin__, List[int]) with self.assertRaises(TypeError): @@ -1207,13 +1191,13 @@ def test_specialize(self): L[int, float] def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) + self.assertEqual(len({te.Annotated[int, 4, 5], te.Annotated[int, 4, 5]}), 1) + self.assertNotEqual(te.Annotated[int, 4, 5], te.Annotated[int, 5, 4]) + self.assertNotEqual(te.Annotated[int, 4, 5], te.Annotated[str, 4, 5]) + self.assertNotEqual(te.Annotated[int, 4], te.Annotated[int, 4, 4]) self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} + {te.Annotated[int, 4, 5], te.Annotated[int, 4, 5], te.Annotated[T, 4, 5]}, + {te.Annotated[int, 4, 5], te.Annotated[T, 4, 5]} ) def test_instantiate(self): @@ -1228,7 +1212,7 @@ def __eq__(self, other): return NotImplemented return other.x == self.x - A = Annotated[C, "a decoration"] + A = te.Annotated[C, "a decoration"] a = A(5) c = C(5) self.assertEqual(a, c) @@ -1236,55 +1220,55 @@ def __eq__(self, other): self.assertEqual(a.classvar, c.classvar) def test_instantiate_generic(self): - MyCount = Annotated[typing_extensions.Counter[T], "my decoration"] + MyCount = te.Annotated[typing_extensions.Counter[T], "my decoration"] self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1}) self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1}) def test_cannot_instantiate_forward(self): - A = Annotated["int", (5, 6)] + A = te.Annotated["int", (5, 6)] with self.assertRaises(TypeError): A(5) def test_cannot_instantiate_type_var(self): - A = Annotated[T, (5, 6)] + A = te.Annotated[T, (5, 6)] with self.assertRaises(TypeError): A(5) def test_cannot_getattr_typevar(self): with self.assertRaises(AttributeError): - Annotated[T, (5, 7)].x + te.Annotated[T, (5, 7)].x def test_attr_passthrough(self): class C: classvar = 4 - A = Annotated[C, "a decoration"] + A = te.Annotated[C, "a decoration"] self.assertEqual(A.classvar, 4) A.x = 5 self.assertEqual(C.x, 5) def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) + self.assertEqual(len({te.Annotated[int, 4, 5], te.Annotated[int, 4, 5]}), 1) + self.assertNotEqual(te.Annotated[int, 4, 5], te.Annotated[int, 5, 4]) + self.assertNotEqual(te.Annotated[int, 4, 5], te.Annotated[str, 4, 5]) + self.assertNotEqual(te.Annotated[int, 4], te.Annotated[int, 4, 4]) self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} + {te.Annotated[int, 4, 5], te.Annotated[int, 4, 5], te.Annotated[T, 4, 5]}, + {te.Annotated[int, 4, 5], te.Annotated[T, 4, 5]} ) def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): - class C(Annotated): + class C(te.Annotated): pass def test_cannot_check_instance(self): with self.assertRaises(TypeError): - isinstance(5, Annotated[int, "positive"]) + isinstance(5, te.Annotated[int, "positive"]) def test_cannot_check_subclass(self): with self.assertRaises(TypeError): - issubclass(int, Annotated[int, "positive"]) + issubclass(int, te.Annotated[int, "positive"]) def test_pickle(self): samples = [typing.Any, typing.Union[int, str], @@ -1292,7 +1276,7 @@ def test_pickle(self): typing.Callable[[str], bytes]] for t in samples: - x = Annotated[t, "a"] + x = te.Annotated[t, "a"] for prot in range(pickle.HIGHEST_PROTOCOL + 1): with self.subTest(protocol=prot, type=t): @@ -1305,7 +1289,7 @@ def test_pickle(self): class _Annotated_test_G(Generic[T]): x = 1 - G = Annotated[_Annotated_test_G[int], "A decoration"] + G = te.Annotated[_Annotated_test_G[int], "A decoration"] G.foo = 42 G.bar = 'abc' @@ -1320,24 +1304,24 @@ def test_subst(self): dec = "a decoration" dec2 = "another decoration" - S = Annotated[T, dec2] - self.assertEqual(S[int], Annotated[int, dec2]) + S = te.Annotated[T, dec2] + self.assertEqual(S[int], te.Annotated[int, dec2]) - self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2]) - L = Annotated[List[T], dec] + self.assertEqual(S[te.Annotated[int, dec]], te.Annotated[int, dec, dec2]) + L = te.Annotated[List[T], dec] - self.assertEqual(L[int], Annotated[List[int], dec]) + self.assertEqual(L[int], te.Annotated[List[int], dec]) with self.assertRaises(TypeError): L[int, int] - self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2]) + self.assertEqual(S[L[int]], te.Annotated[List[int], dec, dec2]) - D = Annotated[Dict[KT, VT], dec] - self.assertEqual(D[str, int], Annotated[Dict[str, int], dec]) + D = te.Annotated[Dict[KT, VT], dec] + self.assertEqual(D[str, int], te.Annotated[Dict[str, int], dec]) with self.assertRaises(TypeError): D[int] - It = Annotated[int, dec] + It = te.Annotated[int, dec] with self.assertRaises(TypeError): It[None] @@ -1346,45 +1330,45 @@ def test_subst(self): LI[None] def test_annotated_in_other_types(self): - X = List[Annotated[T, 5]] - self.assertEqual(X[int], List[Annotated[int, 5]]) + X = List[te.Annotated[T, 5]] + self.assertEqual(X[int], List[te.Annotated[int, 5]]) class GetTypeHintsTests(BaseTestCase): def test_get_type_hints(self): def foobar(x: List['X']): ... - X = Annotated[int, (1, 10)] + X = te.Annotated[int, (1, 10)] self.assertEqual( - get_type_hints(foobar, globals(), locals()), + gth(foobar, globals(), locals()), {'x': List[int]} ) self.assertEqual( - get_type_hints(foobar, globals(), locals(), include_extras=True), - {'x': List[Annotated[int, (1, 10)]]} + gth(foobar, globals(), locals(), include_extras=True), + {'x': List[te.Annotated[int, (1, 10)]]} ) - BA = Tuple[Annotated[T, (1, 0)], ...] + BA = Tuple[te.Annotated[T, (1, 0)], ...] def barfoo(x: BA): ... - self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) + self.assertEqual(gth(barfoo, globals(), locals())['x'], Tuple[T, ...]) self.assertIs( - get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'], + gth(barfoo, globals(), locals(), include_extras=True)['x'], BA ) - def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]], - y: typing.Union[int, Annotated[T, "mutable"]]): ... + def barfoo2(x: typing.Callable[..., te.Annotated[List[T], "const"]], + y: typing.Union[int, te.Annotated[T, "mutable"]]): ... self.assertEqual( - get_type_hints(barfoo2, globals(), locals()), + gth(barfoo2, globals(), locals()), {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]} ) BA2 = typing.Callable[..., List[T]] def barfoo3(x: BA2): ... self.assertIs( - get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"], + gth(barfoo3, globals(), locals(), include_extras=True)["x"], BA2 ) def test_get_type_hints_refs(self): - Const = Annotated[T, "Const"] + Const = te.Annotated[T, "Const"] class MySet(Generic[T]): @@ -1395,17 +1379,17 @@ def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]": ... self.assertEqual( - get_type_hints(MySet.__iand__, globals(), locals()), + gth(MySet.__iand__, globals(), locals()), {'other': MySet[T], 'return': MySet[T]} ) self.assertEqual( - get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True), + gth(MySet.__iand__, globals(), locals(), include_extras=True), {'other': Const[MySet[T]], 'return': MySet[T]} ) self.assertEqual( - get_type_hints(MySet.__ior__, globals(), locals()), + gth(MySet.__ior__, globals(), locals()), {'other': MySet[T], 'return': MySet[T]} ) @@ -1420,52 +1404,52 @@ def test_canonical_usage_with_type_comment(self): def test_cannot_instantiate(self): with self.assertRaises(TypeError): - TypeAlias() + te.TypeAlias() def test_no_isinstance(self): with self.assertRaises(TypeError): - isinstance(42, TypeAlias) + isinstance(42, te.TypeAlias) def test_no_issubclass(self): with self.assertRaises(TypeError): - issubclass(Employee, TypeAlias) + issubclass(Employee, te.TypeAlias) with self.assertRaises(TypeError): - issubclass(TypeAlias, Employee) + issubclass(te.TypeAlias, Employee) def test_cannot_subclass(self): with self.assertRaises(TypeError): - class C(TypeAlias): + class C(te.TypeAlias): pass with self.assertRaises(TypeError): - class C(type(TypeAlias)): + class C(type(te.TypeAlias)): pass def test_repr(self): if hasattr(typing, 'TypeAlias'): - self.assertEqual(repr(TypeAlias), 'typing.TypeAlias') + self.assertEqual(repr(te.TypeAlias), 'typing.TypeAlias') else: - self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias') + self.assertEqual(repr(te.TypeAlias), 'typing_extensions.TypeAlias') def test_cannot_subscript(self): with self.assertRaises(TypeError): - TypeAlias[int] + te.TypeAlias[int] class ParamSpecTests(BaseTestCase): def test_basic_plain(self): - P = ParamSpec('P') + P = te.ParamSpec('P') self.assertEqual(P, P) - self.assertIsInstance(P, ParamSpec) + self.assertIsInstance(P, te.ParamSpec) # Should be hashable hash(P) def test_repr(self): - P = ParamSpec('P') - P_co = ParamSpec('P_co', covariant=True) - P_contra = ParamSpec('P_contra', contravariant=True) - P_2 = ParamSpec('P_2') + P = te.ParamSpec('P') + P_co = te.ParamSpec('P_co', covariant=True) + P_contra = te.ParamSpec('P_contra', contravariant=True) + P_2 = te.ParamSpec('P_2') self.assertEqual(repr(P), '~P') self.assertEqual(repr(P_2), '~P_2') @@ -1475,7 +1459,7 @@ def test_repr(self): self.assertEqual(repr(P_contra), '-P_contra') def test_valid_uses(self): - P = ParamSpec('P') + P = te.ParamSpec('P') T = TypeVar('T') C1 = typing.Callable[P, int] self.assertEqual(C1.__args__, (P, int)) @@ -1501,12 +1485,12 @@ def test_valid_uses(self): self.assertTrue(hasattr(P, 'kwargs')) def test_args_kwargs(self): - P = ParamSpec('P') + P = te.ParamSpec('P') # Note: not in dir(P) because of __class__ hacks self.assertTrue(hasattr(P, 'args')) self.assertTrue(hasattr(P, 'kwargs')) - self.assertIsInstance(P.args, ParamSpecArgs) - self.assertIsInstance(P.kwargs, ParamSpecKwargs) + self.assertIsInstance(P.args, te.ParamSpecArgs) + self.assertIsInstance(P.kwargs, te.ParamSpecKwargs) self.assertIs(P.args.__origin__, P) self.assertIs(P.kwargs.__origin__, P) self.assertEqual(repr(P.args), "P.args") @@ -1514,8 +1498,8 @@ def test_args_kwargs(self): def test_user_generics(self): T = TypeVar("T") - P = ParamSpec("P") - P_2 = ParamSpec("P_2") + P = te.ParamSpec("P") + P_2 = te.ParamSpec("P_2") class X(Generic[T, P]): pass @@ -1524,8 +1508,8 @@ class X(Generic[T, P]): self.assertEqual(G1.__args__, (int, P_2)) self.assertEqual(G1.__parameters__, (P_2,)) - G2 = X[int, Concatenate[int, P_2]] - self.assertEqual(G2.__args__, (int, Concatenate[int, P_2])) + G2 = X[int, te.Concatenate[int, P_2]] + self.assertEqual(G2.__args__, (int, te.Concatenate[int, P_2])) self.assertEqual(G2.__parameters__, (P_2,)) # The following are some valid uses cases in PEP 612 that don't work: @@ -1541,9 +1525,9 @@ class Z(Generic[P]): def test_pickle(self): global P, P_co, P_contra - P = ParamSpec('P') - P_co = ParamSpec('P_co', covariant=True) - P_contra = ParamSpec('P_contra', contravariant=True) + P = te.ParamSpec('P') + P_co = te.ParamSpec('P_co', covariant=True) + P_contra = te.ParamSpec('P_contra', contravariant=True) for proto in range(pickle.HIGHEST_PROTOCOL): with self.subTest(f'Pickle protocol {proto}'): for paramspec in (P, P_co, P_contra): @@ -1554,53 +1538,53 @@ def test_pickle(self): self.assertEqual(z.__bound__, paramspec.__bound__) def test_eq(self): - P = ParamSpec('P') + P = te.ParamSpec('P') self.assertEqual(P, P) self.assertEqual(hash(P), hash(P)) # ParamSpec should compare by id similar to TypeVar in CPython - self.assertNotEqual(ParamSpec('P'), P) - self.assertIsNot(ParamSpec('P'), P) + self.assertNotEqual(te.ParamSpec('P'), P) + self.assertIsNot(te.ParamSpec('P'), P) # Note: normally you don't test this as it breaks when there's # a hash collision. However, ParamSpec *must* guarantee that # as long as two objects don't have the same ID, their hashes # won't be the same. - self.assertNotEqual(hash(ParamSpec('P')), hash(P)) + self.assertNotEqual(hash(te.ParamSpec('P')), hash(P)) class ConcatenateTests(BaseTestCase): def test_basics(self): - P = ParamSpec('P') + P = te.ParamSpec('P') class MyClass: ... - c = Concatenate[MyClass, P] - self.assertNotEqual(c, Concatenate) + c = te.Concatenate[MyClass, P] + self.assertNotEqual(c, te.Concatenate) def test_valid_uses(self): - P = ParamSpec('P') + P = te.ParamSpec('P') T = TypeVar('T') - C1 = typing.Callable[Concatenate[int, P], int] - C2 = typing.Callable[Concatenate[int, T, P], T] + C1 = typing.Callable[te.Concatenate[int, P], int] + C2 = typing.Callable[te.Concatenate[int, T, P], T] # Test collections.abc.Callable too. if sys.version_info[:2] >= (3, 9): - C3 = collections.abc.Callable[Concatenate[int, P], int] - C4 = collections.abc.Callable[Concatenate[int, T, P], T] + C3 = collections.abc.Callable[te.Concatenate[int, P], int] + C4 = collections.abc.Callable[te.Concatenate[int, T, P], T] def test_basic_introspection(self): - P = ParamSpec('P') - C1 = Concatenate[int, P] - C2 = Concatenate[int, T, P] - self.assertEqual(C1.__origin__, Concatenate) + P = te.ParamSpec('P') + C1 = te.Concatenate[int, P] + C2 = te.Concatenate[int, T, P] + self.assertEqual(C1.__origin__, te.Concatenate) self.assertEqual(C1.__args__, (int, P)) - self.assertEqual(C2.__origin__, Concatenate) + self.assertEqual(C2.__origin__, te.Concatenate) self.assertEqual(C2.__args__, (int, T, P)) def test_eq(self): - P = ParamSpec('P') - C1 = Concatenate[int, P] - C2 = Concatenate[int, P] - C3 = Concatenate[int, T, P] + P = te.ParamSpec('P') + C1 = te.Concatenate[int, P] + C2 = te.Concatenate[int, P] + C3 = te.Concatenate[int, T, P] self.assertEqual(C1, C2) self.assertEqual(hash(C1), hash(C2)) self.assertNotEqual(C1, C3) @@ -1608,83 +1592,82 @@ def test_eq(self): class TypeGuardTests(BaseTestCase): def test_basics(self): - TypeGuard[int] # OK - self.assertEqual(TypeGuard[int], TypeGuard[int]) + te.TypeGuard[int] # OK + self.assertEqual(te.TypeGuard[int], te.TypeGuard[int]) - def foo(arg) -> TypeGuard[int]: ... - self.assertEqual(gth(foo), {'return': TypeGuard[int]}) + def foo(arg) -> te.TypeGuard[int]: ... + self.assertEqual(gth(foo), {'return': te.TypeGuard[int]}) def test_repr(self): if hasattr(typing, 'TypeGuard'): mod_name = 'typing' else: mod_name = 'typing_extensions' - self.assertEqual(repr(TypeGuard), f'{mod_name}.TypeGuard') - cv = TypeGuard[int] + self.assertEqual(repr(te.TypeGuard), f'{mod_name}.TypeGuard') + cv = te.TypeGuard[int] self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[int]') - cv = TypeGuard[Employee] + cv = te.TypeGuard[Employee] self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[{__name__}.Employee]') - cv = TypeGuard[Tuple[int]] + cv = te.TypeGuard[Tuple[int]] self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[typing.Tuple[int]]') def test_cannot_subclass(self): with self.assertRaises(TypeError): - class C(type(TypeGuard)): + class C(type(te.TypeGuard)): pass with self.assertRaises(TypeError): - class C(type(TypeGuard[int])): + class C(type(te.TypeGuard[int])): pass def test_cannot_init(self): with self.assertRaises(TypeError): - TypeGuard() + te.TypeGuard() with self.assertRaises(TypeError): - type(TypeGuard)() + type(te.TypeGuard)() with self.assertRaises(TypeError): - type(TypeGuard[Optional[int]])() + type(te.TypeGuard[Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): - isinstance(1, TypeGuard[int]) + isinstance(1, te.TypeGuard[int]) with self.assertRaises(TypeError): - issubclass(int, TypeGuard) - + issubclass(int, te.TypeGuard) class SelfTests(BaseTestCase): def test_basics(self): class Foo: - def bar(self) -> Self: ... + def bar(self) -> te.Self: ... - self.assertEqual(gth(Foo.bar), {'return': Self}) + self.assertEqual(gth(Foo.bar), {'return': te.Self}) def test_repr(self): if hasattr(typing, 'Self'): mod_name = 'typing' else: mod_name = 'typing_extensions' - self.assertEqual(repr(Self), '{}.Self'.format(mod_name)) + self.assertEqual(repr(te.Self), '{}.Self'.format(mod_name)) def test_cannot_subscript(self): with self.assertRaises(TypeError): - Self[int] + te.Self[int] def test_cannot_subclass(self): with self.assertRaises(TypeError): - class C(type(Self)): + class C(type(te.Self)): pass def test_cannot_init(self): with self.assertRaises(TypeError): - Self() + te.Self() with self.assertRaises(TypeError): - type(Self)() + type(te.Self)() def test_no_isinstance(self): with self.assertRaises(TypeError): - isinstance(1, Self) + isinstance(1, te.Self) with self.assertRaises(TypeError): - issubclass(int, Self) + issubclass(int, te.Self) def test_alias(self): TupleSelf = Tuple[Self, Self] @@ -1695,7 +1678,7 @@ def return_tuple(self) -> TupleSelf: class AllTests(BaseTestCase): def test_typing_extensions_includes_standard(self): - a = typing_extensions.__all__ + a = te.__all__ self.assertIn('ClassVar', a) self.assertIn('Type', a) self.assertIn('ChainMap', a) @@ -1727,7 +1710,7 @@ def test_typing_extensions_includes_standard(self): # Check that all objects in `__all__` are present in the module for name in a: - self.assertTrue(hasattr(typing_extensions, name)) + self.assertTrue(hasattr(te, name)) def test_typing_extensions_defers_when_possible(self): exclude = { @@ -1740,10 +1723,10 @@ def test_typing_extensions_defers_when_possible(self): } if sys.version_info < (3, 10): exclude |= {'get_args', 'get_origin'} - for item in typing_extensions.__all__: + for item in te.__all__: if item not in exclude and hasattr(typing, item): self.assertIs( - getattr(typing_extensions, item), + getattr(te, item), getattr(typing, item)) def test_typing_extensions_compiles_with_opt(self): From d60c0db54c85fb1506c7b0f7387c34c3960f9779 Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 11 Nov 2021 23:24:59 +0000 Subject: [PATCH 09/12] Qualify uses of names from typing --- .../src/test_typing_extensions.py | 207 +++++++++--------- 1 file changed, 108 insertions(+), 99 deletions(-) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index 06faa6f0..279418db 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -12,6 +12,15 @@ import typing_extensions as te from typing_extensions import get_type_hints as gth +try: + from typing import _get_protocol_attrs # 3.8+ +except ImportError: + from typing_extensions import _get_protocol_attrs # 3.7 + +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. + # Flags used to mark tests that only apply after a specific # version of the typing module. TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0) @@ -73,7 +82,7 @@ def test_cannot_init(self): with self.assertRaises(TypeError): type(te.Final)() with self.assertRaises(TypeError): - type(te.Final[Optional[int]])() + type(te.Final[typing.Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): @@ -117,7 +126,7 @@ def test_cannot_init(self): with self.assertRaises(TypeError): type(te.Required)() with self.assertRaises(TypeError): - type(te.Required[Optional[int]])() + type(te.Required[typing.Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): @@ -161,7 +170,7 @@ def test_cannot_init(self): with self.assertRaises(TypeError): type(te.NotRequired)() with self.assertRaises(TypeError): - type(te.NotRequired[Optional[int]])() + type(te.NotRequired[typing.Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): @@ -201,8 +210,8 @@ def test_illegal_parameters_do_not_raise_runtime_errors(self): te.Literal[T] def test_literals_inside_other_types(self): - List[te.Literal[1, 2, 3]] - List[te.Literal[("foo", "bar", "baz")]] + typing.List[te.Literal[1, 2, 3]] + typing.List[te.Literal[("foo", "bar", "baz")]] def test_repr(self): if hasattr(typing, 'Literal'): @@ -284,7 +293,7 @@ class Cat(Animal): class GetTypeHintTests(BaseTestCase): def test_get_type_hints_modules(self): - ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} + ann_module_type_hints = {1: 2, 'f': typing.Tuple[int, int], 'x': int, 'y': str} if (TYPING_3_11_0 or (TYPING_3_10_0 and sys.version_info.releaselevel in {'candidate', 'final'})): # More tests were added in 3.10rc1. @@ -295,30 +304,30 @@ def test_get_type_hints_modules(self): def test_get_type_hints_classes(self): self.assertEqual(gth(ann_module.C, ann_module.__dict__), - {'y': Optional[ann_module.C]}) + {'y': typing.Optional[ann_module.C]}) self.assertIsInstance(gth(ann_module.j_class), dict) self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type}) self.assertEqual(gth(ann_module.D), - {'j': str, 'k': str, 'y': Optional[ann_module.C]}) + {'j': str, 'k': str, 'y': typing.Optional[ann_module.C]}) self.assertEqual(gth(ann_module.Y), {'z': int}) self.assertEqual(gth(ann_module.h_class), - {'y': Optional[ann_module.C]}) + {'y': typing.Optional[ann_module.C]}) self.assertEqual(gth(ann_module.S), {'x': str, 'y': str}) self.assertEqual(gth(ann_module.foo), {'x': int}) self.assertEqual(gth(NoneAndForward, globals()), {'parent': NoneAndForward, 'meaning': type(None)}) def test_respect_no_type_check(self): - @no_type_check + @typing.no_type_check class NoTpCheck: class Inn: def __init__(self, x: 'not a type'): ... # noqa self.assertTrue(NoTpCheck.__no_type_check__) self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) self.assertEqual(gth(ann_module2.NTC.meth), {}) - class ABase(Generic[T]): + class ABase(typing.Generic[T]): def meth(x: int): ... - @no_type_check + @typing.no_type_check class Der(ABase): ... self.assertEqual(gth(ABase.meth), {'x': int}) @@ -330,23 +339,23 @@ def test_final_forward_ref(self): class GetUtilitiesTestCase(TestCase): def test_get_origin(self): - T = TypeVar('T') + T = typing.TypeVar('T') P = te.ParamSpec('P') - class C(Generic[T]): pass + class C(typing.Generic[T]): pass self.assertIs(te.get_origin(C[int]), C) self.assertIs(te.get_origin(C[T]), C) self.assertIs(te.get_origin(int), None) - self.assertIs(te.get_origin(ClassVar[int]), ClassVar) - self.assertIs(te.get_origin(Union[int, str]), Union) + self.assertIs(te.get_origin(typing.ClassVar[int]), typing.ClassVar) + self.assertIs(te.get_origin(typing.Union[int, str]), typing.Union) self.assertIs(te.get_origin(te.Literal[42, 43]), te.Literal) - self.assertIs(te.get_origin(te.Final[List[int]]), te.Final) - self.assertIs(te.get_origin(Generic), Generic) - self.assertIs(te.get_origin(Generic[T]), Generic) - self.assertIs(te.get_origin(List[Tuple[T, T]][int]), list) + self.assertIs(te.get_origin(te.Final[typing.List[int]]), te.Final) + self.assertIs(te.get_origin(typing.Generic), typing.Generic) + self.assertIs(te.get_origin(typing.Generic[T]), typing.Generic) + self.assertIs(te.get_origin(typing.List[typing.Tuple[T, T]][int]), list) self.assertIs(te.get_origin(te.Annotated[T, 'thing']), te.Annotated) - self.assertIs(te.get_origin(List), list) - self.assertIs(te.get_origin(Tuple), tuple) - self.assertIs(te.get_origin(Callable), collections.abc.Callable) + self.assertIs(te.get_origin(typing.List), list) + self.assertIs(te.get_origin(typing.Tuple), tuple) + self.assertIs(te.get_origin(typing.Callable), collections.abc.Callable) if sys.version_info >= (3, 9): self.assertIs(te.get_origin(list[int]), list) self.assertIs(te.get_origin(list), None) @@ -354,29 +363,29 @@ class C(Generic[T]): pass self.assertIs(te.get_origin(P.kwargs), P) def test_get_args(self): - T = TypeVar('T') - class C(Generic[T]): pass + T = typing.TypeVar('T') + class C(typing.Generic[T]): pass self.assertEqual(te.get_args(C[int]), (int,)) self.assertEqual(te.get_args(C[T]), (T,)) self.assertEqual(te.get_args(int), ()) - self.assertEqual(te.get_args(ClassVar[int]), (int,)) - self.assertEqual(te.get_args(Union[int, str]), (int, str)) + self.assertEqual(te.get_args(typing.ClassVar[int]), (int,)) + self.assertEqual(te.get_args(typing.Union[int, str]), (int, str)) self.assertEqual(te.get_args(te.Literal[42, 43]), (42, 43)) - self.assertEqual(te.get_args(te.Final[List[int]]), (List[int],)) - self.assertEqual(te.get_args(Union[int, Tuple[T, int]][str]), - (int, Tuple[str, int])) - self.assertEqual(te.get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]), - (int, Tuple[Optional[int], Optional[int]])) - self.assertEqual(te.get_args(Callable[[], T][int]), ([], int)) - self.assertEqual(te.get_args(Callable[..., int]), (..., int)) - self.assertEqual(te.get_args(Union[int, Callable[[Tuple[T, ...]], str]]), - (int, Callable[[Tuple[T, ...]], str])) - self.assertEqual(te.get_args(Tuple[int, ...]), (int, ...)) - self.assertEqual(te.get_args(Tuple[()]), ((),)) + self.assertEqual(te.get_args(te.Final[typing.List[int]]), (typing.List[int],)) + self.assertEqual(te.get_args(typing.Union[int, typing.Tuple[T, int]][str]), + (int, typing.Tuple[str, int])) + self.assertEqual(te.get_args(typing.Dict[int, typing.Tuple[T, T]][typing.Optional[int]]), + (int, typing.Tuple[typing.Optional[int], typing.Optional[int]])) + self.assertEqual(te.get_args(typing.Callable[[], T][int]), ([], int)) + self.assertEqual(te.get_args(typing.Callable[..., int]), (..., int)) + self.assertEqual(te.get_args(typing.Union[int, typing.Callable[[typing.Tuple[T, ...]], str]]), + (int, typing.Callable[[typing.Tuple[T, ...]], str])) + self.assertEqual(te.get_args(typing.Tuple[int, ...]), (int, ...)) + self.assertEqual(te.get_args(typing.Tuple[()]), ((),)) self.assertEqual(te.get_args(te.Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three'])) - self.assertEqual(te.get_args(List), ()) - self.assertEqual(te.get_args(Tuple), ()) - self.assertEqual(te.get_args(Callable), ()) + self.assertEqual(te.get_args(typing.List), ()) + self.assertEqual(te.get_args(typing.Tuple), ()) + self.assertEqual(te.get_args(typing.Callable), ()) if sys.version_info >= (3, 9): self.assertEqual(te.get_args(list[int]), (int,)) self.assertEqual(te.get_args(list), ()) @@ -392,8 +401,8 @@ class C(Generic[T]): pass P = te.ParamSpec('P') # In 3.9 and lower we use typing_extensions's hacky implementation # of ParamSpec, which gets incorrectly wrapped in a list - self.assertIn(te.get_args(Callable[P, int]), [(P, int), ([P], int)]) - self.assertEqual(te.get_args(Callable[te.Concatenate[int, P], int]), + self.assertIn(te.get_args(typing.Callable[P, int]), [(P, int), ([P], int)]) + self.assertEqual(te.get_args(typing.Callable[te.Concatenate[int, P], int]), (te.Concatenate[int, P], int)) @@ -462,7 +471,7 @@ def meth(self, arg: str) -> int: return 1 return 0 -class NT(NamedTuple): +class NT(typing.NamedTuple): x: int y: int @@ -526,7 +535,7 @@ class P(te.Protocol): pass P() class C(P): pass self.assertIsInstance(C(), C) - T = TypeVar('T') + T = typing.TypeVar('T') class PG(te.Protocol[T]): pass with self.assertRaises(TypeError): PG() @@ -607,7 +616,7 @@ def meth2(self): self.assertIsSubclass(C, P) def test_protocols_issubclass(self): - T = TypeVar('T') + T = typing.TypeVar('T') @te.runtime_checkable class P(te.Protocol): def x(self): ... @@ -660,7 +669,7 @@ class D(PNonCall): ... issubclass(D, PNonCall) def test_protocols_isinstance(self): - T = TypeVar('T') + T = typing.TypeVar('T') @te.runtime_checkable class P(te.Protocol): def meth(x): ... @@ -716,7 +725,7 @@ class Bad: pass self.assertIsInstance(NT(1, 2), Position) def test_protocols_isinstance_init(self): - T = TypeVar('T') + T = typing.TypeVar('T') @te.runtime_checkable class P(te.Protocol): x = 1 @@ -814,10 +823,10 @@ class C: pass issubclass(C(), P) def test_defining_generic_protocols_old_style(self): - T = TypeVar('T') - S = TypeVar('S') + T = typing.TypeVar('T') + S = typing.TypeVar('S') @te.runtime_checkable - class PR(te.Protocol, Generic[T, S]): + class PR(te.Protocol, typing.Generic[T, S]): def meth(self): pass class P(PR[int, str], te.Protocol): y = 1 @@ -829,9 +838,9 @@ class P(PR[int, str], te.Protocol): if not TYPING_3_10_0: with self.assertRaises(TypeError): PR[int, 1] - class P1(te.Protocol, Generic[T]): + class P1(te.Protocol, typing.Generic[T]): def bar(self, x: T) -> str: ... - class P2(Generic[T], te.Protocol): + class P2(typing.Generic[T], te.Protocol): def bar(self, x: T) -> str: ... @te.runtime_checkable class PSub(P1[str], te.Protocol): @@ -843,10 +852,10 @@ def bar(self, x: str) -> str: self.assertIsInstance(Test(), PSub) if not TYPING_3_10_0: with self.assertRaises(TypeError): - PR[int, ClassVar] + PR[int, typing.ClassVar] def test_init_called(self): - T = TypeVar('T') + T = typing.TypeVar('T') class P(te.Protocol[T]): pass class C(P[T]): def __init__(self): @@ -854,8 +863,8 @@ def __init__(self): self.assertEqual(C[int]().test, 'OK') def test_protocols_bad_subscripts(self): - T = TypeVar('T') - S = TypeVar('S') + T = typing.TypeVar('T') + S = typing.TypeVar('S') with self.assertRaises(TypeError): class P(te.Protocol[T, T]): pass with self.assertRaises(TypeError): @@ -866,20 +875,20 @@ class P(te.Protocol[T], te.Protocol[S]): pass class P(typing.Mapping[T, S], te.Protocol[T]): pass def test_generic_protocols_repr(self): - T = TypeVar('T') - S = TypeVar('S') + T = typing.TypeVar('T') + S = typing.TypeVar('S') class P(te.Protocol[T, S]): pass self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) def test_generic_protocols_eq(self): - T = TypeVar('T') - S = TypeVar('S') + T = typing.TypeVar('T') + S = typing.TypeVar('S') class P(te.Protocol[T, S]): pass self.assertEqual(P, P) self.assertEqual(P[int, T], P[int, T]) - self.assertEqual(P[T, T][Tuple[T, S]][int, str], - P[Tuple[int, str], Tuple[int, str]]) + self.assertEqual(P[T, T][typing.Tuple[T, S]][int, str], + P[typing.Tuple[int, str], typing.Tuple[int, str]]) def test_generic_protocols_special_from_protocol(self): @te.runtime_checkable @@ -888,7 +897,7 @@ class PR(te.Protocol): class P(te.Protocol): def meth(self): pass - T = TypeVar('T') + T = typing.TypeVar('T') class PG(te.Protocol[T]): x = 1 def meth(self): @@ -903,9 +912,9 @@ def meth(self): self.assertFalse(P._is_runtime_protocol) self.assertTrue(PR._is_runtime_protocol) self.assertTrue(PG[int]._is_protocol) - self.assertEqual(typing_extensions._get_protocol_attrs(P), {'meth'}) - self.assertEqual(typing_extensions._get_protocol_attrs(PR), {'x'}) - self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG)), + self.assertEqual(_get_protocol_attrs(P), {'meth'}) + self.assertEqual(_get_protocol_attrs(PR), {'x'}) + self.assertEqual(frozenset(_get_protocol_attrs(PG)), frozenset({'x', 'meth'})) def test_no_runtime_deco_on_nominal(self): @@ -949,7 +958,7 @@ class P(te.Protocol): def test_protocols_pickleable(self): global P, CP # pickle wants to reference the class by name - T = TypeVar('T') + T = typing.TypeVar('T') @te.runtime_checkable class P(te.Protocol[T]): @@ -1169,7 +1178,7 @@ def test_repr(self): mod_name + ".Annotated[int, 4, 5]" ) self.assertEqual( - repr(te.Annotated[List[int], 4, 5]), + repr(te.Annotated[typing.List[int], 4, 5]), mod_name + ".Annotated[typing.List[int], 4, 5]" ) @@ -1180,11 +1189,11 @@ def test_flatten(self): self.assertEqual(A.__origin__, int) def test_specialize(self): - L = te.Annotated[List[T], "my decoration"] - LI = te.Annotated[List[int], "my decoration"] - self.assertEqual(L[int], te.Annotated[List[int], "my decoration"]) + L = te.Annotated[typing.List[T], "my decoration"] + LI = te.Annotated[typing.List[int], "my decoration"] + self.assertEqual(L[int], te.Annotated[typing.List[int], "my decoration"]) self.assertEqual(L[int].__metadata__, ("my decoration",)) - self.assertEqual(L[int].__origin__, List[int]) + self.assertEqual(L[int].__origin__, typing.List[int]) with self.assertRaises(TypeError): LI[int] with self.assertRaises(TypeError): @@ -1220,7 +1229,7 @@ def __eq__(self, other): self.assertEqual(a.classvar, c.classvar) def test_instantiate_generic(self): - MyCount = te.Annotated[typing_extensions.Counter[T], "my decoration"] + MyCount = te.Annotated[typing.Counter[T], "my decoration"] self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1}) self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1}) @@ -1272,7 +1281,7 @@ def test_cannot_check_subclass(self): def test_pickle(self): samples = [typing.Any, typing.Union[int, str], - typing.Optional[str], Tuple[int, ...], + typing.Optional[str], typing.Tuple[int, ...], typing.Callable[[str], bytes]] for t in samples: @@ -1286,7 +1295,7 @@ def test_pickle(self): global _Annotated_test_G - class _Annotated_test_G(Generic[T]): + class _Annotated_test_G(typing.Generic[T]): x = 1 G = te.Annotated[_Annotated_test_G[int], "A decoration"] @@ -1308,16 +1317,16 @@ def test_subst(self): self.assertEqual(S[int], te.Annotated[int, dec2]) self.assertEqual(S[te.Annotated[int, dec]], te.Annotated[int, dec, dec2]) - L = te.Annotated[List[T], dec] + L = te.Annotated[typing.List[T], dec] - self.assertEqual(L[int], te.Annotated[List[int], dec]) + self.assertEqual(L[int], te.Annotated[typing.List[int], dec]) with self.assertRaises(TypeError): L[int, int] - self.assertEqual(S[L[int]], te.Annotated[List[int], dec, dec2]) + self.assertEqual(S[L[int]], te.Annotated[typing.List[int], dec, dec2]) - D = te.Annotated[Dict[KT, VT], dec] - self.assertEqual(D[str, int], te.Annotated[Dict[str, int], dec]) + D = te.Annotated[typing.Dict[KT, VT], dec] + self.assertEqual(D[str, int], te.Annotated[typing.Dict[str, int], dec]) with self.assertRaises(TypeError): D[int] @@ -1330,36 +1339,36 @@ def test_subst(self): LI[None] def test_annotated_in_other_types(self): - X = List[te.Annotated[T, 5]] - self.assertEqual(X[int], List[te.Annotated[int, 5]]) + X = typing.List[te.Annotated[T, 5]] + self.assertEqual(X[int], typing.List[te.Annotated[int, 5]]) class GetTypeHintsTests(BaseTestCase): def test_get_type_hints(self): - def foobar(x: List['X']): ... + def foobar(x: typing.List['X']): ... X = te.Annotated[int, (1, 10)] self.assertEqual( gth(foobar, globals(), locals()), - {'x': List[int]} + {'x': typing.List[int]} ) self.assertEqual( gth(foobar, globals(), locals(), include_extras=True), - {'x': List[te.Annotated[int, (1, 10)]]} + {'x': typing.List[te.Annotated[int, (1, 10)]]} ) - BA = Tuple[te.Annotated[T, (1, 0)], ...] + BA = typing.Tuple[te.Annotated[T, (1, 0)], ...] def barfoo(x: BA): ... - self.assertEqual(gth(barfoo, globals(), locals())['x'], Tuple[T, ...]) + self.assertEqual(gth(barfoo, globals(), locals())['x'], typing.Tuple[T, ...]) self.assertIs( gth(barfoo, globals(), locals(), include_extras=True)['x'], BA ) - def barfoo2(x: typing.Callable[..., te.Annotated[List[T], "const"]], + def barfoo2(x: typing.Callable[..., te.Annotated[typing.List[T], "const"]], y: typing.Union[int, te.Annotated[T, "mutable"]]): ... self.assertEqual( gth(barfoo2, globals(), locals()), - {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]} + {'x': typing.Callable[..., typing.List[T]], 'y': typing.Union[int, T]} ) - BA2 = typing.Callable[..., List[T]] + BA2 = typing.Callable[..., typing.List[T]] def barfoo3(x: BA2): ... self.assertIs( gth(barfoo3, globals(), locals(), include_extras=True)["x"], @@ -1370,7 +1379,7 @@ def test_get_type_hints_refs(self): Const = te.Annotated[T, "Const"] - class MySet(Generic[T]): + class MySet(typing.Generic[T]): def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]": ... @@ -1460,7 +1469,7 @@ def test_repr(self): def test_valid_uses(self): P = te.ParamSpec('P') - T = TypeVar('T') + T = typing.TypeVar('T') C1 = typing.Callable[P, int] self.assertEqual(C1.__args__, (P, int)) self.assertEqual(C1.__parameters__, (P,)) @@ -1497,11 +1506,11 @@ def test_args_kwargs(self): self.assertEqual(repr(P.kwargs), "P.kwargs") def test_user_generics(self): - T = TypeVar("T") + T = typing.TypeVar("T") P = te.ParamSpec("P") P_2 = te.ParamSpec("P_2") - class X(Generic[T, P]): + class X(typing.Generic[T, P]): pass G1 = X[int, P_2] @@ -1520,7 +1529,7 @@ class X(Generic[T, P]): # Not working because this is special-cased in 3.10. # G6 = Z[int, str, bool] - class Z(Generic[P]): + class Z(typing.Generic[P]): pass def test_pickle(self): @@ -1562,7 +1571,7 @@ class MyClass: ... def test_valid_uses(self): P = te.ParamSpec('P') - T = TypeVar('T') + T = typing.TypeVar('T') C1 = typing.Callable[te.Concatenate[int, P], int] C2 = typing.Callable[te.Concatenate[int, T, P], T] @@ -1608,7 +1617,7 @@ def test_repr(self): self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[int]') cv = te.TypeGuard[Employee] self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[{__name__}.Employee]') - cv = te.TypeGuard[Tuple[int]] + cv = te.TypeGuard[typing.Tuple[int]] self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[typing.Tuple[int]]') def test_cannot_subclass(self): @@ -1625,7 +1634,7 @@ def test_cannot_init(self): with self.assertRaises(TypeError): type(te.TypeGuard)() with self.assertRaises(TypeError): - type(te.TypeGuard[Optional[int]])() + type(te.TypeGuard[typing.Optional[int]])() def test_no_isinstance(self): with self.assertRaises(TypeError): From 6b450a5f4536333fed0c9b04a20c9145675b904b Mon Sep 17 00:00:00 2001 From: AA Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 11 Nov 2021 23:54:57 +0000 Subject: [PATCH 10/12] General clean-up in test_typing_extensions - Inline test helpers - Merge GetTypeHintTests and GetTypeHintsTests - Remove rogue exec call - Remove check given 3.10 has been released --- .../src/test_typing_extensions.py | 250 ++++++++---------- 1 file changed, 114 insertions(+), 136 deletions(-) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index 279418db..c4545e2b 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -27,6 +27,10 @@ TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0) +class Employee: + pass + + class BaseTestCase(TestCase): def assertIsSubclass(self, cls, class_or_tuple, msg=None): if not issubclass(cls, class_or_tuple): @@ -43,10 +47,6 @@ def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): raise self.failureException(message) -class Employee: - pass - - class FinalTests(BaseTestCase): def test_basics(self): @@ -254,88 +254,6 @@ def test_no_multiple_subscripts(self): with self.assertRaises(TypeError): te.Literal[1][1] -class Loop: - attr: te.Final['Loop'] - -class NoneAndForward: - parent: 'NoneAndForward' - meaning: None - -@te.runtime_checkable -class HasCallProtocol(te.Protocol): - __call__: typing.Callable - -Label = te.TypedDict('Label', [('label', str)]) - -class Point2D(te.TypedDict): - x: int - y: int - -class Point2Dor3D(Point2D, total=False): - z: int - -class LabelPoint2D(Point2D, Label): ... - -class Options(te.TypedDict, total=False): - log_level: int - log_path: str - -class BaseAnimal(te.TypedDict): - name: str - -class Animal(BaseAnimal, total=False): - voice: str - tail: bool - -class Cat(Animal): - fur_color: str - - -class GetTypeHintTests(BaseTestCase): - def test_get_type_hints_modules(self): - ann_module_type_hints = {1: 2, 'f': typing.Tuple[int, int], 'x': int, 'y': str} - if (TYPING_3_11_0 - or (TYPING_3_10_0 and sys.version_info.releaselevel in {'candidate', 'final'})): - # More tests were added in 3.10rc1. - ann_module_type_hints['u'] = int | float - self.assertEqual(gth(ann_module), ann_module_type_hints) - self.assertEqual(gth(ann_module2), {}) - self.assertEqual(gth(ann_module3), {}) - - def test_get_type_hints_classes(self): - self.assertEqual(gth(ann_module.C, ann_module.__dict__), - {'y': typing.Optional[ann_module.C]}) - self.assertIsInstance(gth(ann_module.j_class), dict) - self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type}) - self.assertEqual(gth(ann_module.D), - {'j': str, 'k': str, 'y': typing.Optional[ann_module.C]}) - self.assertEqual(gth(ann_module.Y), {'z': int}) - self.assertEqual(gth(ann_module.h_class), - {'y': typing.Optional[ann_module.C]}) - self.assertEqual(gth(ann_module.S), {'x': str, 'y': str}) - self.assertEqual(gth(ann_module.foo), {'x': int}) - self.assertEqual(gth(NoneAndForward, globals()), - {'parent': NoneAndForward, 'meaning': type(None)}) - - def test_respect_no_type_check(self): - @typing.no_type_check - class NoTpCheck: - class Inn: - def __init__(self, x: 'not a type'): ... # noqa - self.assertTrue(NoTpCheck.__no_type_check__) - self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) - self.assertEqual(gth(ann_module2.NTC.meth), {}) - class ABase(typing.Generic[T]): - def meth(x: int): ... - @typing.no_type_check - class Der(ABase): ... - self.assertEqual(gth(ABase.meth), {'x': int}) - - def test_final_forward_ref(self): - self.assertEqual(gth(Loop, globals())['attr'], te.Final[Loop]) - self.assertNotEqual(gth(Loop, globals())['attr'], te.Final[int]) - self.assertNotEqual(gth(Loop, globals())['attr'], te.Final) - class GetUtilitiesTestCase(TestCase): def test_get_origin(self): @@ -430,52 +348,6 @@ class MyOrdDict(te.OrderedDict[str, int]): self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict) -class Coordinate(te.Protocol): - x: int - y: int - -@te.runtime_checkable -class Point(Coordinate, te.Protocol): - label: str - -class MyPoint: - x: int - y: int - label: str - -class XAxis(te.Protocol): - x: int - -class YAxis(te.Protocol): - y: int - -@te.runtime_checkable -class Position(XAxis, YAxis, te.Protocol): - pass - -@te.runtime_checkable -class Proto(te.Protocol): - attr: int - - def meth(self, arg: str) -> int: - ... - -class Concrete(Proto): - pass - -class Other: - attr: int = 1 - - def meth(self, arg: str) -> int: - if arg == 'this': - return 1 - return 0 - -class NT(typing.NamedTuple): - x: int - y: int - - class ProtocolTests(BaseTestCase): def test_basic_protocol(self): @@ -508,6 +380,9 @@ def f(): self.assertIsInstance(thing, Empty) def test_function_implements_protocol(self): + @te.runtime_checkable + class HasCallProtocol(te.Protocol): + __call__: typing.Callable def f(): pass self.assertIsInstance(f, HasCallProtocol) @@ -694,6 +569,24 @@ def meth(x): ... isinstance(C(), BadPG) def test_protocols_isinstance_py36(self): + class Coordinate(te.Protocol): + x: int + y: int + @te.runtime_checkable + class Point(Coordinate, te.Protocol): + label: str + class XAxis(te.Protocol): + x: int + class YAxis(te.Protocol): + y: int + @te.runtime_checkable + class Position(XAxis, YAxis, te.Protocol): + pass + @te.runtime_checkable + class Proto(te.Protocol): + attr: int + def meth(self, arg: str) -> int: ... + class APoint: def __init__(self, x, y, label): self.x = x @@ -704,12 +597,26 @@ class BPoint: def __init__(self, x, y): self.x = x self.y = y + class MyPoint: + x: int + y: int + label: str + class Other: + attr: int = 1 + def meth(self, arg: str) -> int: + if arg == 'this': + return 1 + return 0 + class Concrete(Proto): pass class C: def __init__(self, attr): self.attr = attr def meth(self, arg): return 0 class Bad: pass + class NT(typing.NamedTuple): + x: int + y: int self.assertIsInstance(APoint(1, 2, 'A'), Point) self.assertIsInstance(BPoint(1, 2), Point) self.assertNotIsInstance(MyPoint(), Point) @@ -1094,6 +1001,11 @@ def test_typeddict_errors(self): te.TypedDict('Hi', [('x', int)], y=int) def test_py36_class_syntax_usage(self): + class Point2D(te.TypedDict): + x: int + y: int + Label = te.TypedDict('Label', [('label', str)]) + class LabelPoint2D(Point2D, Label): ... self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D') self.assertEqual(LabelPoint2D.__module__, __name__) self.assertEqual(gth(LabelPoint2D), {'x': int, 'y': int, 'label': str}) @@ -1133,6 +1045,9 @@ def test_total(self): self.assertEqual(D.__required_keys__, frozenset()) self.assertEqual(D.__optional_keys__, {'x'}) + class Options(te.TypedDict, total=False): + log_level: int + log_path: str self.assertEqual(Options(), {}) self.assertEqual(Options(log_level=2), {'log_level': 2}) self.assertEqual(Options.__total__, False) @@ -1140,10 +1055,25 @@ def test_total(self): self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'}) def test_optional_keys(self): + class Point2D(te.TypedDict): + x: int + y: int + class Point2Dor3D(Point2D, total=False): + z: int assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y']) assert Point2Dor3D.__optional_keys__ == frozenset(['z']) def test_keys_inheritance(self): + class BaseAnimal(te.TypedDict): + name: str + + class Animal(BaseAnimal, total=False): + voice: str + tail: bool + + class Cat(Animal): + fur_color: str + assert BaseAnimal.__required_keys__ == frozenset(['name']) assert BaseAnimal.__optional_keys__ == frozenset([]) assert gth(BaseAnimal) == {'name': str} @@ -1344,7 +1274,34 @@ def test_annotated_in_other_types(self): class GetTypeHintsTests(BaseTestCase): - def test_get_type_hints(self): + def test_get_type_hints_modules(self): + ann_module_type_hints = {1: 2, 'f': typing.Tuple[int, int], 'x': int, 'y': str} + if TYPING_3_10_0: + ann_module_type_hints['u'] = int | float + self.assertEqual(gth(ann_module), ann_module_type_hints) + self.assertEqual(gth(ann_module2), {}) + self.assertEqual(gth(ann_module3), {}) + + def test_get_type_hints_classes(self): + class NoneAndForward: + parent: 'NoneAndForward' + meaning: None + + self.assertEqual(gth(ann_module.C, ann_module.__dict__), + {'y': typing.Optional[ann_module.C]}) + self.assertIsInstance(gth(ann_module.j_class), dict) + self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type}) + self.assertEqual(gth(ann_module.D), + {'j': str, 'k': str, 'y': typing.Optional[ann_module.C]}) + self.assertEqual(gth(ann_module.Y), {'z': int}) + self.assertEqual(gth(ann_module.h_class), + {'y': typing.Optional[ann_module.C]}) + self.assertEqual(gth(ann_module.S), {'x': str, 'y': str}) + self.assertEqual(gth(ann_module.foo), {'x': int}) + self.assertEqual(gth(NoneAndForward, locals()), + {'parent': NoneAndForward, 'meaning': type(None)}) + + def test_get_type_hints_functions(self): def foobar(x: typing.List['X']): ... X = te.Annotated[int, (1, 10)] self.assertEqual( @@ -1375,6 +1332,27 @@ def barfoo3(x: BA2): ... BA2 ) + def test_respect_no_type_check(self): + @typing.no_type_check + class NoTpCheck: + class Inn: + def __init__(self, x: 'not a type'): ... # noqa + self.assertTrue(NoTpCheck.__no_type_check__) + self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) + self.assertEqual(gth(ann_module2.NTC.meth), {}) + class ABase(typing.Generic[T]): + def meth(x: int): ... + @typing.no_type_check + class Der(ABase): ... + self.assertEqual(gth(ABase.meth), {'x': int}) + + def test_final_forward_ref(self): + class Loop: + attr: te.Final['Loop'] + self.assertEqual(gth(Loop, locals())['attr'], te.Final[Loop]) + self.assertNotEqual(gth(Loop, locals())['attr'], te.Final[int]) + self.assertNotEqual(gth(Loop, locals())['attr'], te.Final) + def test_get_type_hints_refs(self): Const = te.Annotated[T, "Const"] @@ -1405,8 +1383,7 @@ def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]": class TypeAliasTests(BaseTestCase): def test_canonical_usage_with_variable_annotation(self): - ns = {} - exec('Alias: TypeAlias = Employee', globals(), ns) + Alias: te.TypeAlias = Employee def test_canonical_usage_with_type_comment(self): Alias = Employee # type: TypeAlias @@ -1445,6 +1422,7 @@ def test_cannot_subscript(self): with self.assertRaises(TypeError): te.TypeAlias[int] + class ParamSpecTests(BaseTestCase): def test_basic_plain(self): @@ -1679,7 +1657,7 @@ def test_no_isinstance(self): issubclass(int, te.Self) def test_alias(self): - TupleSelf = Tuple[Self, Self] + TupleSelf = typing.Tuple[te.Self, te.Self] class Alias: def return_tuple(self) -> TupleSelf: return (self, self) From e4dad5a80d5cdcd27b98d362a285085502c790b6 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 4 Jan 2022 12:46:17 +0000 Subject: [PATCH 11/12] Make `KT` and `VT` private --- typing_extensions/CHANGELOG | 2 ++ typing_extensions/src/typing_extensions.py | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG index fb46b9d5..9107c91e 100644 --- a/typing_extensions/CHANGELOG +++ b/typing_extensions/CHANGELOG @@ -10,9 +10,11 @@ unneeded for supporting Python 3.7 and newer. - PEP_560 - GenericMeta +- KT - T - T_co - T_contra +- VT # Release 4.0.1 (November 30, 2021) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index d868319c..ef818e4d 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -78,11 +78,6 @@ Deque = typing.Deque DefaultDict = typing.DefaultDict -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. - class _ReprForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -176,7 +171,11 @@ def __getitem__(self, parameters): OrderedDict = typing.OrderedDict # 3.7.0-3.7.2 else: - OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) + # Some unconstrained type variables. + # (These are not for export.) + _KT = typing.TypeVar('_KT') # Key type. + _VT = typing.TypeVar('_VT') # Value type. + OrderedDict = typing._alias(collections.OrderedDict, (_KT, _VT)) _PROTO_WHITELIST = ['Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', From 1a19539fe69489cb6650db1a65aaa6cd4b1d8002 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 15 Jan 2022 23:49:21 +0000 Subject: [PATCH 12/12] Update version number --- typing_extensions/CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG index 9107c91e..f689d0e3 100644 --- a/typing_extensions/CHANGELOG +++ b/typing_extensions/CHANGELOG @@ -1,9 +1,9 @@ -# Changes in version 5.0.0 +# Changes in version 4.2.0 Dropped support for Python 3.6 and simplified backports for Python 3.7.0 and newer. Patch by Adam Turner (@AA-Turner). -## Removed in version 5.0.0 +## Removed in version 4.2.0 The following non-exported but non-private names have been removed as they are unneeded for supporting Python 3.7 and newer.