From 8b41f2478144fcc32bac7a65afc3e490c24bb068 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Tue, 9 Nov 2021 18:43:03 +0000 Subject: [PATCH 01/12] Add Self type --- .../src_py3/typing_extensions.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/typing_extensions/src_py3/typing_extensions.py b/typing_extensions/src_py3/typing_extensions.py index 184da0ad..76f5850a 100644 --- a/typing_extensions/src_py3/typing_extensions.py +++ b/typing_extensions/src_py3/typing_extensions.py @@ -2844,3 +2844,50 @@ def is_str(val: Union[str, float]): PEP 647 (User-Defined Type Guards). """ __type__ = None + + +if hasattr(typing, "Self"): + Self = typing.Self + +elif hasattr(typing, "_SpecialForm"): + @typing._SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + 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. + + 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) From 70bd506b7159337323b453403e438fad44c40694 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 09:25:18 +0000 Subject: [PATCH 02/12] Fix 3.7-3.8 --- .../src_py3/typing_extensions.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/typing_extensions/src_py3/typing_extensions.py b/typing_extensions/src_py3/typing_extensions.py index 76f5850a..ee9ae41d 100644 --- a/typing_extensions/src_py3/typing_extensions.py +++ b/typing_extensions/src_py3/typing_extensions.py @@ -2849,7 +2849,7 @@ def is_str(val: Union[str, float]): if hasattr(typing, "Self"): Self = typing.Self -elif hasattr(typing, "_SpecialForm"): +elif sys.version_info[:2] >= (3, 9): @typing._SpecialForm def Self(self, params): """Used to spell the type of "self" in classes. @@ -2867,6 +2867,26 @@ def parse(self, data: bytes) -> Self: 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. From 5236e47540dfe5c072ee20d08a594076f81474e2 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:50:57 +0000 Subject: [PATCH 03/12] Add tests and a changelog entry --- typing_extensions/CHANGELOG | 2 + .../src_py3/test_typing_extensions.py | 38 ++++++++++++++++++- .../src_py3/typing_extensions.py | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG index d8820afa..1170f38c 100644 --- a/typing_extensions/CHANGELOG +++ b/typing_extensions/CHANGELOG @@ -2,3 +2,5 @@ Starting with version 4.0.0, typing_extensions uses Semantic Versioning. See the README for more information. + +- Add runtime support for PEP 673 and `typing_extensions.Self`. diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index 75bdb8eb..65081b50 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -12,7 +12,7 @@ from typing import Tuple, List, Dict, Iterator, Callable from typing import Generic from typing import no_type_check -from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict +from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard try: @@ -2195,6 +2195,42 @@ def test_no_isinstance(self): issubclass(int, TypeGuard) + +class SelfTests(BaseTestCase): + def test_basics(self): + class Foo: + def bar(self) -> Self: ... + + self.assertEqual(gth(Foo.bar), {'return': 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)) + + def test_cannot_subscript(self): + with self.assertRaises(TypeError): + Self[int] + + def test_cannot_subclass(self): + with self.assertRaises(TypeError): + class C(type(Self)): + pass + + def test_cannot_init(self): + with self.assertRaises(TypeError): + Self() + with self.assertRaises(TypeError): + type(Self)() + + def test_no_isinstance(self): + with self.assertRaises(TypeError): + isinstance(1, Self) + with self.assertRaises(TypeError): + issubclass(int, 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 ee9ae41d..98cc7b29 100644 --- a/typing_extensions/src_py3/typing_extensions.py +++ b/typing_extensions/src_py3/typing_extensions.py @@ -119,6 +119,7 @@ def _check_methods_in_mro(C, *methods): 'Concatenate', 'Final', 'ParamSpec', + 'Self', 'Type', # ABCs (from collections.abc). From c42e4eacceab381ac418569026712891ba7ce757 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:07:44 +0000 Subject: [PATCH 04/12] Fix repr on 3.9 --- typing_extensions/src_py3/typing_extensions.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/typing_extensions/src_py3/typing_extensions.py b/typing_extensions/src_py3/typing_extensions.py index 98cc7b29..61b5f858 100644 --- a/typing_extensions/src_py3/typing_extensions.py +++ b/typing_extensions/src_py3/typing_extensions.py @@ -2851,7 +2851,11 @@ def is_str(val: Union[str, float]): Self = typing.Self elif sys.version_info[:2] >= (3, 9): - @typing._SpecialForm + class _SelfForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_SelfForm def Self(self, params): """Used to spell the type of "self" in classes. From 5c8ae7a90005593c0591e853ced24c84320ac42a Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:00:27 +0000 Subject: [PATCH 05/12] Change to . imports --- .../src_py3/test_typing_extensions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index 65081b50..08a26e58 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -12,24 +12,24 @@ from typing import Tuple, List, Dict, Iterator, Callable from typing import Generic from typing import no_type_check -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 NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self +from .typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard try: - from typing_extensions import Protocol, runtime, runtime_checkable + from .typing_extensions import Protocol, runtime, runtime_checkable except ImportError: pass try: - from typing_extensions import Annotated + from .typing_extensions import Annotated except ImportError: pass try: - from typing_extensions import get_type_hints + from .typing_extensions import get_type_hints except ImportError: - from typing import get_type_hints + from .typing import get_type_hints import typing -import typing_extensions +from . import typing_extensions import collections.abc as collections_abc PEP_560 = sys.version_info[:3] >= (3, 7, 0) From e8d9134c78141f13dc5d23c217405137175f30be Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:08:03 +0000 Subject: [PATCH 06/12] Try fully qualified versions --- typing_extensions/src_py3/test_typing_extensions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index 08a26e58..97d04fc7 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -12,24 +12,24 @@ from typing import Tuple, List, Dict, Iterator, Callable from typing import Generic from typing import no_type_check -from .typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self -from .typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard +from src_py3.typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self +from src_py3.typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard try: - from .typing_extensions import Protocol, runtime, runtime_checkable + from src_py3.typing_extensions import Protocol, runtime, runtime_checkable except ImportError: pass try: - from .typing_extensions import Annotated + from src_py3.typing_extensions import Annotated except ImportError: pass try: - from .typing_extensions import get_type_hints + from src_py3.typing_extensions import get_type_hints except ImportError: from .typing import get_type_hints import typing -from . import typing_extensions +from src_py3. import typing_extensions import collections.abc as collections_abc PEP_560 = sys.version_info[:3] >= (3, 7, 0) From ee2e8741d704e85f52ba371f01fdcdf419ca62f0 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:11:23 +0000 Subject: [PATCH 07/12] Whoops --- typing_extensions/src_py3/test_typing_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index 97d04fc7..e8ba1a69 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -29,7 +29,7 @@ from .typing import get_type_hints import typing -from src_py3. import typing_extensions +from src_py3 import typing_extensions import collections.abc as collections_abc PEP_560 = sys.version_info[:3] >= (3, 7, 0) From a1abaf026bcd4576c3d0efd524c5ae2927da7b63 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:13:57 +0000 Subject: [PATCH 08/12] Not sure how I managed that --- typing_extensions/src_py3/test_typing_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index e8ba1a69..21fa545b 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -26,7 +26,7 @@ try: from src_py3.typing_extensions import get_type_hints except ImportError: - from .typing import get_type_hints + from typing import get_type_hints import typing from src_py3 import typing_extensions From 59399a2caf8e6f1c70df5165b44aed36d23407f4 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:23:47 +0000 Subject: [PATCH 09/12] Update ci.yml --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70c69cff..6286fdf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,8 @@ jobs: run: | pip install --upgrade pip pip install -r test-requirements.txt + pip uninstall typing-extensions + # other libraries in the requirements can depend on typing-extensions so we need to unistall it before testing - name: Test typing_extensions run: pytest typing_extensions/src_py3 From 610b289b30508f0dca984957ede22be38b852959 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:24:41 +0000 Subject: [PATCH 10/12] Fix imports again --- typing_extensions/src_py3/test_typing_extensions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py index 21fa545b..65081b50 100644 --- a/typing_extensions/src_py3/test_typing_extensions.py +++ b/typing_extensions/src_py3/test_typing_extensions.py @@ -12,24 +12,24 @@ from typing import Tuple, List, Dict, Iterator, Callable from typing import Generic from typing import no_type_check -from src_py3.typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self -from src_py3.typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard +from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self +from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard try: - from src_py3.typing_extensions import Protocol, runtime, runtime_checkable + from typing_extensions import Protocol, runtime, runtime_checkable except ImportError: pass try: - from src_py3.typing_extensions import Annotated + from typing_extensions import Annotated except ImportError: pass try: - from src_py3.typing_extensions import get_type_hints + from typing_extensions import get_type_hints except ImportError: from typing import get_type_hints import typing -from src_py3 import typing_extensions +import typing_extensions import collections.abc as collections_abc PEP_560 = sys.version_info[:3] >= (3, 7, 0) From f7952b4fb4624b6fb76823592020457f5c036dab Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 11 Nov 2021 07:32:11 -0800 Subject: [PATCH 11/12] fix interactive uninstall --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6286fdf2..37b2a189 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: run: | pip install --upgrade pip pip install -r test-requirements.txt - pip uninstall typing-extensions + pip uninstall -y typing-extensions # other libraries in the requirements can depend on typing-extensions so we need to unistall it before testing - name: Test typing_extensions From 5c2fc62fac9e6a22ef76657abbb6c52ac6146475 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 11 Nov 2021 20:50:40 +0000 Subject: [PATCH 12/12] Remove call to uninstall --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37b2a189..70c69cff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,8 +38,6 @@ jobs: run: | pip install --upgrade pip pip install -r test-requirements.txt - pip uninstall -y typing-extensions - # other libraries in the requirements can depend on typing-extensions so we need to unistall it before testing - name: Test typing_extensions run: pytest typing_extensions/src_py3