From e07c76782340d9f3411539d69a3564b22383ec5e Mon Sep 17 00:00:00 2001 From: Chris Wesseling Date: Fri, 26 Nov 2021 16:44:16 +0100 Subject: [PATCH] Vendor typing._SpecialForm to fool typing._type_check Adds a local copy of _SpecialForm in our namespace, so typing._type_check won't raise TypeError. (#964) --- .../src_py3/test_typing_extensions.py | 6 ++ .../src_py3/typing_extensions.py | 64 +++++++++++++------ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index 2fc5b3f2a..731f97317 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -2199,6 +2199,12 @@ def test_no_isinstance(self): with self.assertRaises(TypeError): issubclass(int, Self) + def test_alias(self): + TupleSelf = Tuple[Self, Self] + class Alias: + def return_tuple(self) -> TupleSelf: + return (self, self) + class AllTests(BaseTestCase): def test_typing_extensions_includes_standard(self): diff --git a/typing_extensions/src_py3/typing_extensions.py b/typing_extensions/src_py3/typing_extensions.py index 15fec259d..13bf7df73 100644 --- a/typing_extensions/src_py3/typing_extensions.py +++ b/typing_extensions/src_py3/typing_extensions.py @@ -2048,40 +2048,61 @@ def __eq__(self, other): TypeGuard = _TypeGuard(_root=True) +if not hasattr(typing, "Self") and sys.version_info[:2] >= (3, 7): + # Vendored from cpython typing._SpecialFrom + class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') -if hasattr(typing, "Self"): - Self = typing.Self + 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 + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") -elif sys.version_info[:2] >= (3, 9): - class _SelfForm(typing._SpecialForm, _root=True): def __repr__(self): - return 'typing_extensions.' + self._name + return 'typing.' + self._name - @_SelfForm - def Self(self, params): - """Used to spell the type of "self" in classes. + def __reduce__(self): + return self._name - Example:: + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") - from typing import Self + def __or__(self, other): + return Union[self, other] - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self + def __ror__(self, other): + return Union[other, self] - """ + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") - raise TypeError(f"{self} is not subscriptable") + 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) + +if hasattr(typing, "Self"): + Self = typing.Self elif sys.version_info[:2] >= (3, 7): - class _SelfForm(typing._SpecialForm, _root=True): + class _SelfForm(_SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name - Self = _SelfForm( - "Self", - doc="""Used to spell the type of "self" in classes. + @_SelfForm + def Self(self, params): + """Used to spell the type of "self" in classes. Example:: @@ -2093,7 +2114,8 @@ def parse(self, data: bytes) -> Self: return self """ - ) + + raise TypeError(f"{self} is not subscriptable") else: class _Self(typing._FinalTypingBase, _root=True): """Used to spell the type of "self" in classes.