diff options
author | Jelle Zijlstra <jelle.zijlstra@gmail.com> | 2022-03-17 01:09:58 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-17 09:09:58 +0100 |
commit | 0ca0e458324ed27f96d81265faf94595f57d84af (patch) | |
tree | ea8ceab394926738436068772dde37c635772b94 | |
parent | 95c9c2bab2034f0359e8457360d93a288a65e55d (diff) | |
download | typing-0ca0e458324ed27f96d81265faf94595f57d84af.tar.gz |
typing-extensions: Drop Python 3.6 (#1104)
-rw-r--r-- | .github/workflows/ci.yml | 2 | ||||
-rw-r--r-- | CONTRIBUTING.md | 2 | ||||
-rw-r--r-- | typing_extensions/CHANGELOG | 4 | ||||
-rw-r--r-- | typing_extensions/README.rst | 9 | ||||
-rw-r--r-- | typing_extensions/pyproject.toml | 2 | ||||
-rw-r--r-- | typing_extensions/src/test_typing_extensions.py | 90 | ||||
-rw-r--r-- | typing_extensions/src/typing_extensions.py | 1205 |
7 files changed, 108 insertions, 1206 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0e6d67..302b2ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: # Python version, because typing sometimes changed between bugfix releases. # For available versions, see: # https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - python-version: ["3.6", "3.6.7", "3.7", "3.7.1", "3.8", "3.8.0", "3.9", "3.9.0", "3.10", "3.10.0", "3.11-dev"] + python-version: ["3.7", "3.7.1", "3.8", "3.8.0", "3.9", "3.9.0", "3.10", "3.10.0", "3.11-dev"] runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63c5034..095e826 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 d27af29..f098464 100644 --- a/typing_extensions/CHANGELOG +++ b/typing_extensions/CHANGELOG @@ -1,3 +1,7 @@ +# Unreleased + +- Drop support for Python 3.6. Original patch by Adam Turner (@AA-Turner). + # Release 4.1.1 (February 13, 2022) - Fix importing `typing_extensions` on Python 3.7.0 and 3.7.1. Original diff --git a/typing_extensions/README.rst b/typing_extensions/README.rst index 5db69d1..bb89068 100644 --- a/typing_extensions/README.rst +++ b/typing_extensions/README.rst @@ -30,6 +30,10 @@ Therefore, it's safe to depend on ``typing_extensions`` like this: ``typing_extensions >=x.y, <(x+1)``, where ``x.y`` is the first version that includes all features you need. +``typing_extensions`` supports Python versions 3.7 and higher. In the future, +support for older Python versions will be dropped some time after that version +reaches end of life. + Included items ============== @@ -101,7 +105,7 @@ This module currently contains the following: - ``Text`` - ``Type`` - ``TYPE_CHECKING`` - - ``get_type_hints`` (``typing_extensions`` provides this function only in Python 3.7+) + - ``get_type_hints`` Other Notes and Limitations =========================== @@ -131,9 +135,6 @@ versions of the typing module: - ``ParamSpec`` and ``Concatenate`` will not work with ``get_args`` and ``get_origin``. Certain PEP 612 special cases in user-defined ``Generic``\ s are also not available. -- ``Unpack`` from PEP 646 does not work properly with user-defined - ``Generic``\ s in Python 3.6: ``class X(Generic[Unpack[Ts]]):`` does - not work. These types are only guaranteed to work for static type checking. diff --git a/typing_extensions/pyproject.toml b/typing_extensions/pyproject.toml index fd6e185..fbd0180 100644 --- a/typing_extensions/pyproject.toml +++ b/typing_extensions/pyproject.toml @@ -9,7 +9,7 @@ name = "typing_extensions" version = "4.1.1" description = "Backported and Experimental Type Hints for Python 3.6+" readme = "README.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 = [ diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index a66a2f2..20e35f4 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -23,32 +23,14 @@ from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload, final, is_typeddict from typing_extensions import TypeVarTuple, Unpack, dataclass_transform, reveal_type, Never, assert_never, LiteralString -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, get_origin, get_args # 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_8_0 = sys.version_info[:3] >= (3, 8, 0) 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): @@ -78,9 +60,7 @@ class BottomTypeTestsMixin: self.assertIs(self.bottom_type, self.bottom_type) self.assertNotEqual(self.bottom_type, None) - @skipUnless(PEP_560, "Python 3.7+ required") def test_get_origin(self): - from typing_extensions import get_origin self.assertIs(get_origin(self.bottom_type), None) def test_instance_type_error(self): @@ -621,11 +601,8 @@ class GetTypeHintTests(BaseTestCase): 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 - T = TypeVar('T') P = ParamSpec('P') Ts = TypeVarTuple('Ts') @@ -655,8 +632,6 @@ class GetUtilitiesTestCase(TestCase): self.assertIs(get_origin(Unpack), None) def test_get_args(self): - from typing_extensions import get_args - T = TypeVar('T') Ts = TypeVarTuple('Ts') class C(Generic[T]): pass @@ -767,7 +742,6 @@ class CollectionsAbcTests(BaseTestCase): 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()), @@ -790,7 +764,6 @@ class CollectionsAbcTests(BaseTestCase): 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()), @@ -844,10 +817,7 @@ class CollectionsAbcTests(BaseTestCase): 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): @@ -922,9 +892,8 @@ class OtherABCTests(BaseTestCase): 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] @@ -1189,10 +1158,6 @@ class ProtocolTests(BaseTestCase): 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): @@ -1383,7 +1348,6 @@ class ProtocolTests(BaseTestCase): 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') @@ -1392,16 +1356,19 @@ class ProtocolTests(BaseTestCase): 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] + issubclass(PR[int, T], PR) with self.assertRaises(TypeError): - P[int, str] + issubclass(P[str], PR) with self.assertRaises(TypeError): - PR[int, 1] + PR[int] with self.assertRaises(TypeError): - PR[int, ClassVar] + P[int, str] + if not TYPING_3_10_0: + 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) @@ -1413,11 +1380,8 @@ class ProtocolTests(BaseTestCase): 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] @@ -1448,7 +1412,6 @@ class ProtocolTests(BaseTestCase): 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') @@ -1465,9 +1428,6 @@ class ProtocolTests(BaseTestCase): 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]')) @@ -1480,13 +1440,10 @@ class ProtocolTests(BaseTestCase): 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) @@ -1517,9 +1474,6 @@ class ProtocolTests(BaseTestCase): 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): @@ -1747,7 +1701,6 @@ class TypedDictTests(BaseTestCase): assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y']) assert Point2Dor3D.__optional_keys__ == frozenset(['z']) - @skipUnless(PEP_560, "runtime support for Required and NotRequired requires PEP 560") def test_required_notrequired_keys(self): assert NontotalMovie.__required_keys__ == frozenset({'title'}) assert NontotalMovie.__optional_keys__ == frozenset({'year'}) @@ -1821,16 +1774,14 @@ class AnnotatedTests(BaseTestCase): 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): @@ -1934,7 +1885,6 @@ class AnnotatedTests(BaseTestCase): 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, ...], @@ -2000,7 +1950,6 @@ class AnnotatedTests(BaseTestCase): 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']): ... @@ -2355,9 +2304,7 @@ class LiteralStringTests(BaseTestCase): self.assertEqual(gth(Foo.bar), {'return': LiteralString}) self.assertEqual(gth(Foo.baz), {'return': LiteralString}) - @skipUnless(PEP_560, "Python 3.7+ required") def test_get_origin(self): - from typing_extensions import get_origin self.assertIsNone(get_origin(LiteralString)) def test_repr(self): @@ -2510,7 +2457,6 @@ class UnpackTests(BaseTestCase): Union ) - @skipUnless(PEP_560, "Unimplemented for 3.6") def test_concatenation(self): Xs = TypeVarTuple('Xs') self.assertEqual(Tuple[int, Unpack[Xs]].__args__, (int, Unpack[Xs])) @@ -2523,7 +2469,6 @@ class UnpackTests(BaseTestCase): self.assertEqual(C[int, Unpack[Xs], str].__args__, (int, Unpack[Xs], str)) - @skipUnless(PEP_560, "Unimplemented for 3.6") def test_class(self): Ts = TypeVarTuple('Ts') @@ -2766,8 +2711,7 @@ class AllTests(BaseTestCase): 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 194731c..5c43354 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -6,17 +6,6 @@ import sys import types as _types 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 - # Please keep __all__ alphabetized within each category. __all__ = [ @@ -56,6 +45,9 @@ __all__ = [ 'assert_never', 'dataclass_transform', 'final', + 'get_args', + 'get_origin', + 'get_type_hints', 'IntVar', 'is_typeddict', 'Literal', @@ -75,21 +67,13 @@ __all__ = [ 'NotRequired', ] -if PEP_560: - __all__.extend(["get_args", "get_origin", "get_type_hints"]) +# for backward compatibility +PEP_560 = True +GenericMeta = type # The functions below are modified copies of typing internal helpers. # They are needed by _ProtocolMeta and they provide support for PEP 646. - -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 - - _marker = object() @@ -148,32 +132,7 @@ def _collect_type_vars(types, typevar_types=None): return tuple(tvars) -# 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.) @@ -190,7 +149,7 @@ ClassVar = typing.ClassVar if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): Final = typing.Final # 3.7 -elif sys.version_info[:2] >= (3, 7): +else: class _FinalForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -215,61 +174,6 @@ elif sys.version_info[:2] >= (3, 7): 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) - if sys.version_info >= (3, 11): final = typing.final @@ -317,7 +221,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): @@ -339,55 +243,6 @@ elif sys.version_info[:2] >= (3, 7): 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 @@ -401,154 +256,30 @@ Type = typing.Type # 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__ = () - - 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__ = () + 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 -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', @@ -582,7 +313,7 @@ def _is_callable_members_only(cls): if hasattr(typing, 'Protocol'): Protocol = typing.Protocol # 3.7 -elif PEP_560: +else: def _no_init(self, *args, **kwargs): if type(self)._is_protocol: @@ -764,250 +495,12 @@ elif PEP_560: 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, len(self.__parameters__)) - 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 @@ -1031,7 +524,7 @@ runtime = runtime_checkable # 3.8+ if hasattr(typing, 'SupportsIndex'): SupportsIndex = typing.SupportsIndex -# 3.6-3.7 +# 3.7 else: @runtime_checkable class SupportsIndex(Protocol): @@ -1148,29 +641,22 @@ else: optional_keys.update(base.__dict__.get('__optional_keys__', ())) annotations.update(own_annotations) - if PEP_560: - for annotation_key, annotation_type in own_annotations.items(): - annotation_origin = get_origin(annotation_type) - if annotation_origin is Annotated: - annotation_args = get_args(annotation_type) - if annotation_args: - annotation_type = annotation_args[0] - annotation_origin = get_origin(annotation_type) - - if annotation_origin is Required: - required_keys.add(annotation_key) - elif annotation_origin is NotRequired: - optional_keys.add(annotation_key) - elif total: - required_keys.add(annotation_key) - else: - optional_keys.add(annotation_key) - else: - own_annotation_keys = set(own_annotations.keys()) - if total: - required_keys.update(own_annotation_keys) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) else: - optional_keys.update(own_annotation_keys) + optional_keys.add(annotation_key) tp_dict.__annotations__ = annotations tp_dict.__required_keys__ = frozenset(required_keys) @@ -1233,7 +719,7 @@ else: if hasattr(typing, "Required"): get_type_hints = typing.get_type_hints -elif PEP_560: +else: import functools import types @@ -1312,7 +798,7 @@ if hasattr(typing, 'Annotated'): # 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. @@ -1409,152 +895,6 @@ elif PEP_560: raise TypeError( f"Cannot subclass {cls.__module__}.Annotated" ) -# 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: - if ( - isinstance(params[0], typing._TypingBase) and - type(params[0]).__name__ == "_ClassVar" - ): - tp = params[0] - 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 @@ -1563,7 +903,7 @@ if sys.version_info[:2] >= (3, 10): 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 @@ -1645,7 +985,7 @@ elif sys.version_info[:2] >= (3, 9): """ 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 @@ -1661,44 +1001,13 @@ elif sys.version_info[:2] >= (3, 7): 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.""" @@ -1759,7 +1068,7 @@ else: # 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. @@ -1861,28 +1170,17 @@ else: 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) @@ -1907,14 +1205,8 @@ if not hasattr(typing, 'Concatenate'): 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 == (): @@ -1949,7 +1241,7 @@ elif sys.version_info[:2] >= (3, 9): """ 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 @@ -1969,42 +1261,6 @@ elif sys.version_info[:2] >= (3, 7): 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'): @@ -2062,7 +1318,7 @@ elif sys.version_info[:2] >= (3, 9): 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): @@ -2117,138 +1373,55 @@ elif sys.version_info[:2] >= (3, 7): ``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__',) +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') - def __init__(self, tp=None, **kwds): - self.__type__ = tp + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ - 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 sys.version_info[:2] >= (3, 7): - # Vendored from cpython typing._SpecialFrom - class _SpecialForm(typing._Final, _root=True): - __slots__ = ('_name', '__doc__', '_getitem') - - def __init__(self, getitem): - self._getitem = getitem - self._name = getitem.__name__ - self.__doc__ = getitem.__doc__ - - def __getattr__(self, item): - if item in {'__name__', '__qualname__'}: - return self._name + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name - raise AttributeError(item) + raise AttributeError(item) - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass {self!r}") + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") - def __repr__(self): - return f'typing_extensions.{self._name}' + def __repr__(self): + return f'typing_extensions.{self._name}' - def __reduce__(self): - return self._name + def __reduce__(self): + return self._name - def __call__(self, *args, **kwds): - raise TypeError(f"Cannot instantiate {self!r}") + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") - def __or__(self, other): - return typing.Union[self, other] + def __or__(self, other): + return typing.Union[self, other] - def __ror__(self, other): - return typing.Union[other, self] + def __ror__(self, other): + return typing.Union[other, self] - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance()") + 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()") + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") - @typing._tp_cache - def __getitem__(self, parameters): - return self._getitem(self, parameters) + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) if hasattr(typing, "LiteralString"): LiteralString = typing.LiteralString -elif sys.version_info[:2] >= (3, 7): +else: @_SpecialForm def LiteralString(self, params): """Represents an arbitrary literal string. @@ -2267,38 +1440,11 @@ elif sys.version_info[:2] >= (3, 7): """ raise TypeError(f"{self} is not subscriptable") -else: - class _LiteralString(typing._FinalTypingBase, _root=True): - """Represents an arbitrary literal string. - - Example:: - - from typing_extensions import LiteralString - - def query(sql: LiteralString) -> ...: - ... - - query("SELECT * FROM table") # ok - query(f"SELECT * FROM {input()}") # not ok - - See PEP 675 for details. - - """ - - __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().") - - LiteralString = _LiteralString(_root=True) if hasattr(typing, "Self"): Self = typing.Self -elif sys.version_info[:2] >= (3, 7): +else: @_SpecialForm def Self(self, params): """Used to spell the type of "self" in classes. @@ -2315,35 +1461,11 @@ elif sys.version_info[:2] >= (3, 7): """ 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, "Never"): Never = typing.Never -elif sys.version_info[:2] >= (3, 7): +else: @_SpecialForm def Never(self, params): """The bottom type, a type that has no members. @@ -2369,39 +1491,6 @@ elif sys.version_info[:2] >= (3, 7): """ raise TypeError(f"{self} is not subscriptable") -else: - class _Never(typing._FinalTypingBase, _root=True): - """The bottom type, a type that has no members. - - This can be used to define a function that should never be - called, or a function that never returns:: - - from typing_extensions import Never - - def never_call_me(arg: Never) -> None: - pass - - def int_or_str(arg: int | str) -> None: - never_call_me(arg) # type checker error - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - never_call_me(arg) # ok, arg is of type Never - - """ - - __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().") - - Never = _Never(_root=True) if hasattr(typing, 'Required'): @@ -2449,7 +1538,7 @@ elif sys.version_info[:2] >= (3, 9): item = typing._type_check(parameters, f'{self._name} accepts only single type') return typing._GenericAlias(self, (item,)) -elif sys.version_info[:2] >= (3, 7): +else: class _RequiredForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name @@ -2490,78 +1579,6 @@ elif sys.version_info[:2] >= (3, 7): 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) if sys.version_info[:2] >= (3, 9): @@ -2590,7 +1607,7 @@ if sys.version_info[:2] >= (3, 9): def _is_unpack(obj): return isinstance(obj, _UnpackAlias) -elif sys.version_info[:2] >= (3, 7): +else: class _UnpackAlias(typing._GenericAlias, _root=True): __class__ = typing.TypeVar @@ -2619,64 +1636,6 @@ elif sys.version_info[:2] >= (3, 7): def _is_unpack(obj): return isinstance(obj, _UnpackAlias) -else: - # NOTE: Modeled after _Final's implementation when _FinalTypingBase available - class _Unpack(typing._FinalTypingBase, _root=True): - """A special typing construct to unpack a variadic type. For example: - - Shape = TypeVarTuple('Shape') - Batch = NewType('Batch', int) - - def add_batch_axis( - x: Array[Unpack[Shape]] - ) -> Array[Batch, Unpack[Shape]]: ... - - """ - __slots__ = ('__type__',) - __class__ = typing.TypeVar - - 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, - 'Unpack accepts only single type.'), - _root=True) - raise TypeError('Unpack 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 += '[{}]'.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, _Unpack): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - # For 3.6 only - def _get_type_vars(self, tvars): - self.__type__._get_type_vars(tvars) - - Unpack = _Unpack(_root=True) - - def _is_unpack(obj): - return isinstance(obj, _Unpack) - class TypeVarTuple: """Type variable tuple. @@ -2757,12 +1716,6 @@ class TypeVarTuple: if '_root' not in kwds: raise TypeError("Cannot subclass special typing classes") - if not PEP_560: - # Only needed in 3.6. - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) - if hasattr(typing, "reveal_type"): reveal_type = typing.reveal_type |