Vendor typing._SpecialForm to fool typing._type_check (#966)
Adds a local copy of _SpecialForm in our namespace, so
typing._type_check won't raise TypeError. (#964)
Co-authored-by: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com>
diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py
index 2fc5b3f..731f973 100644
--- a/src/test_typing_extensions.py
+++ b/src/test_typing_extensions.py
@@ -2199,6 +2199,12 @@
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/src/typing_extensions.py b/src/typing_extensions.py
index 15fec25..9f1c7aa 100644
--- a/src/typing_extensions.py
+++ b/src/typing_extensions.py
@@ -2048,16 +2048,53 @@
TypeGuard = _TypeGuard(_root=True)
-
if hasattr(typing, "Self"):
Self = typing.Self
+elif sys.version_info[:2] >= (3, 7):
+ # Vendored from cpython typing._SpecialFrom
+ class _SpecialForm(typing._Final, _root=True):
+ __slots__ = ('_name', '__doc__', '_getitem')
-elif sys.version_info[:2] >= (3, 9):
- class _SelfForm(typing._SpecialForm, _root=True):
+ 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}")
+
def __repr__(self):
- return 'typing_extensions.' + self._name
+ return f'typing_extensions.{self._name}'
- @_SelfForm
+ def __reduce__(self):
+ return self._name
+
+ def __call__(self, *args, **kwds):
+ raise TypeError(f"Cannot instantiate {self!r}")
+
+ def __or__(self, other):
+ return typing.Union[self, other]
+
+ def __ror__(self, other):
+ return typing.Union[other, self]
+
+ 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()")
+
+ @typing._tp_cache
+ def __getitem__(self, parameters):
+ return self._getitem(self, parameters)
+
+ @_SpecialForm
def Self(self, params):
"""Used to spell the type of "self" in classes.
@@ -2073,27 +2110,6 @@
"""
raise TypeError(f"{self} is not subscriptable")
-
-elif sys.version_info[:2] >= (3, 7):
- class _SelfForm(typing._SpecialForm, _root=True):
- def __repr__(self):
- return 'typing_extensions.' + self._name
-
- Self = _SelfForm(
- "Self",
- doc="""Used to spell the type of "self" in classes.
-
- Example::
-
- from typing import Self
-
- class ReturnsSelf:
- def parse(self, data: bytes) -> Self:
- ...
- return self
-
- """
- )
else:
class _Self(typing._FinalTypingBase, _root=True):
"""Used to spell the type of "self" in classes.