diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index 2fc5b3f2a..731f97317 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/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/typing_extensions.py b/typing_extensions/src/typing_extensions.py index 15fec259d..9f1c7aa31 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -2048,40 +2048,55 @@ def __eq__(self, other): 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') + + 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 f'typing_extensions.{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 typing.Union[self, other] - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self + def __ror__(self, other): + return typing.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()") -elif sys.version_info[:2] >= (3, 7): - class _SelfForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) - Self = _SelfForm( - "Self", - doc="""Used to spell the type of "self" in classes. + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. Example:: @@ -2093,7 +2108,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.