From c273968b66d0ee1458b9947ba9abcf24ec960ca7 Mon Sep 17 00:00:00 2001 From: Randolf Scholz Date: Sun, 2 Nov 2025 11:13:41 +0100 Subject: [PATCH 1/2] fixed NotImplementedType regression --- stdlib/@tests/test_cases/check_types.py | 13 +++++++++++++ stdlib/builtins.pyi | 18 +++++++++--------- stdlib/types.pyi | 4 ++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/stdlib/@tests/test_cases/check_types.py b/stdlib/@tests/test_cases/check_types.py index 847c38c387ac..3bcceb1a2891 100644 --- a/stdlib/@tests/test_cases/check_types.py +++ b/stdlib/@tests/test_cases/check_types.py @@ -62,6 +62,9 @@ def foo(self) -> None: self._value = None +# check that NotImplemented is treated as an "Any" +x: int = NotImplemented + if sys.version_info > (3, 10): union_type = int | list[_T] @@ -70,3 +73,13 @@ def foo(self) -> None: # Both mypy and pyright special-case this operation, # but in different ways, so we just check that no error is emitted: _ = union_type[int] + + # test NotImplementedType usage + assert_type(NotImplemented, types.NotImplementedType) + _: types.NotImplementedType = types.NotImplementedType() + # test EllipsisType usage + assert_type(Ellipsis, types.EllipsisType) + _: types.EllipsisType = types.EllipsisType() + # test NoneType usage + assert_type(None, types.NoneType) + _: None = types.NoneType() diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 835ab3a74c44..2ab74bd976d5 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1367,13 +1367,6 @@ class property: def __set__(self, instance: Any, value: Any, /) -> None: ... def __delete__(self, instance: Any, /) -> None: ... -@final -@type_check_only -class _NotImplementedType(Any): - __call__: None - -NotImplemented: _NotImplementedType - def abs(x: SupportsAbs[_T], /) -> _T: ... def all(iterable: Iterable[object], /) -> bool: ... def any(iterable: Iterable[object], /) -> bool: ... @@ -2032,14 +2025,14 @@ def __import__( def __build_class__(func: Callable[[], CellType | Any], name: str, /, *bases: Any, metaclass: Any = ..., **kwds: Any) -> Any: ... if sys.version_info >= (3, 10): - from types import EllipsisType + from types import EllipsisType, NotImplementedType # Backwards compatibility hack for folks who relied on the ellipsis type # existing in typeshed in Python 3.9 and earlier. ellipsis = EllipsisType Ellipsis: EllipsisType - + NotImplemented: NotImplementedType else: # Actually the type of Ellipsis is , but since it's # not exposed anywhere under that name, we make it private here. @@ -2049,6 +2042,13 @@ else: Ellipsis: ellipsis + @final + @type_check_only + class _NotImplementedType(Any): + __call__: None + + NotImplemented: _NotImplementedType + @disjoint_base class BaseException: args: tuple[Any, ...] diff --git a/stdlib/types.pyi b/stdlib/types.pyi index 649e463ff71f..0293e5cb0b4b 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -717,9 +717,9 @@ if sys.version_info >= (3, 10): @final class EllipsisType: ... - from builtins import _NotImplementedType + @final + class NotImplementedType(Any): ... - NotImplementedType = _NotImplementedType @final class UnionType: @property From 50d35674caf1bacfe9a7b4dd6a83eac8ab015a2e Mon Sep 17 00:00:00 2001 From: Randolf Scholz Date: Sun, 2 Nov 2025 11:26:18 +0100 Subject: [PATCH 2/2] fixed unit test --- stdlib/@tests/test_cases/check_types.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/stdlib/@tests/test_cases/check_types.py b/stdlib/@tests/test_cases/check_types.py index 3bcceb1a2891..884557c74b88 100644 --- a/stdlib/@tests/test_cases/check_types.py +++ b/stdlib/@tests/test_cases/check_types.py @@ -65,7 +65,18 @@ def foo(self) -> None: # check that NotImplemented is treated as an "Any" x: int = NotImplemented -if sys.version_info > (3, 10): +if sys.version_info >= (3, 10): + # test NotImplementedType usage + assert_type(NotImplemented, types.NotImplementedType) + assert_type(types.NotImplementedType(), types.NotImplementedType) + # test EllipsisType usage + assert_type(Ellipsis, types.EllipsisType) + assert_type(types.EllipsisType(), types.EllipsisType) + # test NoneType usage (disabled, passes with pyright, but mypy errors + # assert_type(None, types.NoneType) + # assert_type(types.NoneType(), types.NoneType) + +if sys.version_info >= (3, 11): union_type = int | list[_T] # ideally this would be `_SpecialForm` (Union) @@ -73,13 +84,3 @@ def foo(self) -> None: # Both mypy and pyright special-case this operation, # but in different ways, so we just check that no error is emitted: _ = union_type[int] - - # test NotImplementedType usage - assert_type(NotImplemented, types.NotImplementedType) - _: types.NotImplementedType = types.NotImplementedType() - # test EllipsisType usage - assert_type(Ellipsis, types.EllipsisType) - _: types.EllipsisType = types.EllipsisType() - # test NoneType usage - assert_type(None, types.NoneType) - _: None = types.NoneType()