From 40e75814f98454b568da5d0fd1b9396e166eb671 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Mon, 24 Jan 2022 23:17:56 +0000 Subject: [PATCH 01/10] Implementation of PEP 637 Self Tests were copied from typing_extensions Co-authored-by: Pradeep Kumar Srinivasan --- Doc/library/typing.rst | 18 ++++++++++++++++++ Lib/test/test_typing.py | 38 +++++++++++++++++++++++++++++++++++++- Lib/typing.py | 21 ++++++++++++++++++++- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 08b59d84246f8d..d6437348f0a146 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -68,6 +68,8 @@ annotations. These include: *Introducing* :data:`TypeAlias` * :pep:`647`: User-Defined Type Guards *Introducing* :data:`TypeGuard` +* :pep:`673`: Self type + *Introducing* :data:`Self` .. _type-aliases: @@ -585,6 +587,22 @@ These can be used as types in annotations and do not support ``[]``. .. versionadded:: 3.5.4 .. versionadded:: 3.6.2 +.. data:: Self + + Special annotation to represent the current enclosed class. + For Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self) -> Self: + ... + return self + + For more info see :pep:`673`. + + .. versionadded:: 3.11 + .. data:: TypeAlias Special annotation for explicitly declaring a :ref:`type alias `. diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a94d77d4edf4be..53ce6de6c452b5 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -25,6 +25,7 @@ from typing import IO, TextIO, BinaryIO from typing import Pattern, Match from typing import Annotated, ForwardRef +from typing import Self from typing import TypeAlias from typing import ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs from typing import TypeGuard @@ -155,8 +156,43 @@ def test_cannot_instantiate(self): type(NoReturn)() -class TypeVarTests(BaseTestCase): +class SelfTests(BaseTestCase): + def test_basics(self): + class Foo: + def bar(self) -> Self: ... + + self.assertEqual(gth(Foo.bar), {'return': Self}) + + def test_repr(self): + self.assertEqual(repr(Self), 'typing.Self') + + 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) + def test_alias(self): + Tuple[Self, Self] + List[Self] + + +class TypeVarTests(BaseTestCase): def test_basic_plain(self): T = TypeVar('T') # T equals itself. diff --git a/Lib/typing.py b/Lib/typing.py index ae1dd5c2d76891..ad3d2a6707b873 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -131,6 +131,7 @@ def _idfunc(_, x): 'ParamSpecArgs', 'ParamSpecKwargs', 'runtime_checkable', + 'Self', 'Text', 'TYPE_CHECKING', 'TypeAlias', @@ -173,7 +174,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, is_class=False): if (isinstance(arg, _GenericAlias) and arg.__origin__ in invalid_generic_forms): raise TypeError(f"{arg} is not valid as type argument") - if arg in (Any, NoReturn, Final): + if arg in (Any, NoReturn, Self, Final): return arg if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol): raise TypeError(f"Plain {arg} is not valid as type argument") @@ -446,6 +447,24 @@ def stop() -> NoReturn: """ raise TypeError(f"{self} is not subscriptable") + +@_SpecialForm +def Self(self, parameters): + """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") + + @_SpecialForm def ClassVar(self, parameters): """Special type construct to mark class variables. From 72c1341972d2044be6b188d8a83994b304bd9540 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 26 Jan 2022 18:06:09 +0000 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst diff --git a/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst b/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst new file mode 100644 index 00000000000000..c496836dbec5c1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst @@ -0,0 +1 @@ +Implement PEP 673 :class:`typing.Self`. \ No newline at end of file From 9afb1a5ca5c3e5e32cfd88453ab37f8d9691ca3c Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Thu, 27 Jan 2022 20:08:25 +0000 Subject: [PATCH 03/10] Respond to feedback --- Doc/library/typing.rst | 17 +++++++++++++---- Lib/test/test_typing.py | 9 +++++++-- Lib/typing.py | 7 +++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index d6437348f0a146..fd4b66d2f2720c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -589,16 +589,25 @@ These can be used as types in annotations and do not support ``[]``. .. data:: Self - Special annotation to represent the current enclosed class. - For Example:: + Special type to represent the current enclosed class. + For example:: from typing import Self - class ReturnsSelf: - def parse(self) -> Self: + class Foo: + def returns_self(self) -> Self: ... return self + .. note:: + + This code would be semantically equivalent to a bound :class:`TypeVar` with the `bound=Foo`. + + This is especially useful for: + + - :class:`classmethod`\s that are used as alternative constructors + - Annotating an :meth:`object.__enter__` method which returns self + For more info see :pep:`673`. .. versionadded:: 3.11 diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 53ce6de6c452b5..f607cb67d9f554 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -188,8 +188,13 @@ def test_no_isinstance(self): issubclass(int, Self) def test_alias(self): - Tuple[Self, Self] - List[Self] + # TypeAliases are not actually part of the spec + alias_1 = Tuple[Self, Self] + alias_2 = List[Self] + alias_3 = ClassVar[Self] + self.assertEqual(get_args(alias_1) == (Self, Self)) + self.assertEqual(get_args(alias_2) == (Self,)) + self.assertEqual(get_args(alias_3) == (Self,)) class TypeVarTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index ad3d2a6707b873..998ea34b0cd13f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -456,11 +456,14 @@ def Self(self, parameters): from typing import Self - class ReturnsSelf: - def parse(self, data: bytes) -> Self: + class Foo: + def returns_self(self) -> Self: ... return self + This is especially useful for: + - classmethods that are used as alternative constructors + - annotating an `__enter__` method which returns self """ raise TypeError(f"{self} is not subscriptable") From f4366e57edaa0e2bc69f80de7393479b61764d20 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Thu, 27 Jan 2022 21:08:44 +0000 Subject: [PATCH 04/10] Fix typo --- Lib/test/test_typing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f607cb67d9f554..5414ebced05d1b 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -192,9 +192,9 @@ def test_alias(self): alias_1 = Tuple[Self, Self] alias_2 = List[Self] alias_3 = ClassVar[Self] - self.assertEqual(get_args(alias_1) == (Self, Self)) - self.assertEqual(get_args(alias_2) == (Self,)) - self.assertEqual(get_args(alias_3) == (Self,)) + self.assertEqual(get_args(alias_1), (Self, Self)) + self.assertEqual(get_args(alias_2), (Self,)) + self.assertEqual(get_args(alias_3), (Self,)) class TypeVarTests(BaseTestCase): From a16c329ee83c5bbbf80fb227540b1227e3ec0061 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Sun, 30 Jan 2022 19:29:53 +0000 Subject: [PATCH 05/10] Update Doc/library/typing.rst Co-authored-by: Jelle Zijlstra --- Doc/library/typing.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index fd4b66d2f2720c..34d92a463bd226 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -599,16 +599,15 @@ These can be used as types in annotations and do not support ``[]``. ... return self - .. note:: - This code would be semantically equivalent to a bound :class:`TypeVar` with the `bound=Foo`. + This annotation is semantically equivalent to using a :class:`TypeVar` with `bound=Foo` as both the return annotation and the annotation for the `self` parameter. - This is especially useful for: + Common use cases include: - :class:`classmethod`\s that are used as alternative constructors - Annotating an :meth:`object.__enter__` method which returns self - For more info see :pep:`673`. + For more information, see :pep:`673`. .. versionadded:: 3.11 From 5613e8b3c8ddddc17cc479d2a859d540caa06dad Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Sun, 30 Jan 2022 19:45:53 +0000 Subject: [PATCH 06/10] Shorten line length --- Doc/library/typing.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 34d92a463bd226..318046ba873827 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -600,7 +600,8 @@ These can be used as types in annotations and do not support ``[]``. return self - This annotation is semantically equivalent to using a :class:`TypeVar` with `bound=Foo` as both the return annotation and the annotation for the `self` parameter. + This annotation is semantically equivalent to using a :class:`TypeVar` with `bound=Foo` as + both the return annotation and the annotation for the `self` parameter. Common use cases include: From 4dbba7e60555c3a989dd2b73f0ace9c31ed99faf Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Mon, 31 Jan 2022 09:22:07 +0000 Subject: [PATCH 07/10] Fix docs failing --- Doc/library/typing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 93c3f647eaefd4..c74338bb79cc7d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -600,8 +600,8 @@ These can be used as types in annotations and do not support ``[]``. return self - This annotation is semantically equivalent to using a :class:`TypeVar` with `bound=Foo` as - both the return annotation and the annotation for the `self` parameter. + This annotation is semantically equivalent to using a :class:`TypeVar` with ``bound=Foo`` as + both the return annotation and the annotation for the ``self`` parameter. Common use cases include: From 5c3e674d0c400faddb6013a6db647aa29104c09f Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Wed, 2 Feb 2022 13:13:29 +0000 Subject: [PATCH 08/10] Add an entry in whatschanged --- Doc/whatsnew/3.11.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 5389ce8b258cf8..4ec2efc3148a6d 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -67,6 +67,8 @@ Summary -- Release highlights PEP-654: Exception Groups and ``except*``. (Contributed by Irit Katriel in :issue:`45292`.) +PEP-673: ``Self`` Type. +(Contributed by James Hilton-Balfe and Pradeep Kumar in :issue:`30924`.) New Features ============ From 2b7e7cf90f9e86756135228133bd842244109fc0 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <50501825+Gobot1234@users.noreply.github.com> Date: Mon, 7 Feb 2022 12:36:03 +0000 Subject: [PATCH 09/10] Improve the documentation further --- Doc/library/typing.rst | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c74338bb79cc7d..b0ecddaf8f2ee3 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -600,13 +600,33 @@ These can be used as types in annotations and do not support ``[]``. return self - This annotation is semantically equivalent to using a :class:`TypeVar` with ``bound=Foo`` as - both the return annotation and the annotation for the ``self`` parameter. + This annotation is semantically equivalent to the following, + albeit in a more succinct fashion:: - Common use cases include: + from typing import TypeVar - - :class:`classmethod`\s that are used as alternative constructors - - Annotating an :meth:`object.__enter__` method which returns self + Self = TypeVar("Self", bound="Foo") + + class Foo: + def returns_self(self: Self) -> Self: + ... + return self + + In general if something currently follows the pattern of:: + + class Foo: + def return_self(self) -> "Foo": + ... + return self + + You should use use :data:`Self` as calls to ``SubclassOfFoo.returns_self`` would have + ``Foo`` as the return type and not ``SubclassOfFoo``. + + Other common use cases include: + + - :class:`classmethod`\s that are used as alternative constructors and return instances + of the ``cls`` parameter. + - Annotating an :meth:`object.__enter__` method which returns self. For more information, see :pep:`673`. From 2d23126751288dbc81e6bf9f8d8125ffa8ecec3f Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Mon, 7 Feb 2022 12:37:39 +0000 Subject: [PATCH 10/10] Update the news entry --- .../next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst b/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst index c496836dbec5c1..35a70aae170045 100644 --- a/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst +++ b/Misc/NEWS.d/next/Library/2022-01-26-18-06-08.bpo-46534.vhzUM4.rst @@ -1 +1,2 @@ -Implement PEP 673 :class:`typing.Self`. \ No newline at end of file +Implement :pep:`673` :class:`typing.Self`. +Patch by James Hilton-Balfe.