diff --git a/Lib/typing.py b/Lib/typing.py index 75ec2a6a2e..47112a6a1a 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -122,6 +122,7 @@ 'ParamSpecArgs', 'ParamSpecKwargs', 'runtime_checkable', + 'Self', 'Text', 'TYPE_CHECKING', 'TypeAlias', @@ -164,7 +165,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms= 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, TypeAlias): + if arg in (Any, NoReturn, Final, Self, TypeAlias): return arg if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol): raise TypeError(f"Plain {arg} is not valid as type argument") @@ -438,6 +439,25 @@ 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 Foo: + def return_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") + @_SpecialForm def ClassVar(self, parameters): """Special type construct to mark class variables. diff --git a/extra_tests/snippets/stdlib_typing.py b/extra_tests/snippets/stdlib_typing.py new file mode 100644 index 0000000000..0dd5f40ce0 --- /dev/null +++ b/extra_tests/snippets/stdlib_typing.py @@ -0,0 +1,8 @@ +from typing import Self + +class Shape: + def set_scale(self, scale: float) -> Self: + self.scale = scale + return self + +print(Shape().set_scale(3).scale)