diff --git a/stdlib/@tests/test_cases/builtins/check_reversed.py b/stdlib/@tests/test_cases/builtins/check_reversed.py index 2a43a57deb4e..d89ebf3a0ca7 100644 --- a/stdlib/@tests/test_cases/builtins/check_reversed.py +++ b/stdlib/@tests/test_cases/builtins/check_reversed.py @@ -31,4 +31,18 @@ def __getitem__(self, item: int) -> _T: len_and_get_item: MyLenAndGetItem[int] = MyLenAndGetItem() -assert_type(list(reversed(len_and_get_item)), "list[int]") +assert_type(reversed(len_and_get_item), "reversed[int]") + + +class UnTrue: + def __reversed__(self) -> UnFalse: + return UnFalse() + + +class UnFalse: + def __reversed__(self) -> UnTrue: + return UnTrue() + + +assert_type(reversed(UnTrue()), "UnFalse") +assert_type(reversed(reversed(UnTrue())), "UnTrue") diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index fbecb8454ae0..9512864ac345 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -30,7 +30,7 @@ from _typeshed import ( SupportsRichComparisonT, SupportsWrite, ) -from collections.abc import Awaitable, Callable, Iterable, Iterator, MutableSet, Reversible, Set as AbstractSet, Sized +from collections.abc import Awaitable, Callable, Iterable, Iterator, MutableSet, Set as AbstractSet, Sized from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper from os import PathLike from types import CellType, CodeType, EllipsisType, GenericAlias, NotImplementedType, TracebackType, UnionType @@ -281,6 +281,7 @@ class int: *, signed: bool = False, ) -> Self: ... + else: def to_bytes(self, length: SupportsIndex, byteorder: Literal["little", "big"], *, signed: bool = False) -> bytes: ... @classmethod @@ -344,6 +345,7 @@ class int: def __floor__(self) -> int: ... if sys.version_info >= (3, 14): def __round__(self, ndigits: SupportsIndex | None = None, /) -> int: ... + else: def __round__(self, ndigits: SupportsIndex = ..., /) -> int: ... @@ -770,6 +772,7 @@ class bytes(Sequence[int]): def partition(self, sep: ReadableBuffer, /) -> tuple[bytes, bytes, bytes]: ... if sys.version_info >= (3, 15): def replace(self, old: ReadableBuffer, new: ReadableBuffer, /, count: SupportsIndex = -1) -> bytes: ... + else: def replace(self, old: ReadableBuffer, new: ReadableBuffer, count: SupportsIndex = -1, /) -> bytes: ... @@ -890,6 +893,7 @@ class bytearray(MutableSequence[int]): def removesuffix(self, suffix: ReadableBuffer, /) -> bytearray: ... if sys.version_info >= (3, 15): def replace(self, old: ReadableBuffer, new: ReadableBuffer, /, count: SupportsIndex = -1) -> bytearray: ... + else: def replace(self, old: ReadableBuffer, new: ReadableBuffer, count: SupportsIndex = -1, /) -> bytearray: ... @@ -1042,6 +1046,7 @@ class memoryview(Sequence[_I]): if sys.version_info >= (3, 14): def index(self, value: object, start: SupportsIndex = 0, stop: SupportsIndex = sys.maxsize, /) -> int: ... def count(self, value: object, /) -> int: ... + else: # These are inherited from the Sequence ABC, but don't actually exist on memoryview. # See https://github.com/python/cpython/issues/125420 @@ -1128,6 +1133,7 @@ class slice(Generic[_StartT_co, _StopT_co, _StepT_co]): def __eq__(self, value: object, /) -> bool: ... if sys.version_info >= (3, 12): def __hash__(self) -> int: ... + else: __hash__: ClassVar[None] # type: ignore[assignment] @@ -1202,6 +1208,7 @@ class function: closure: tuple[CellType, ...] | None = None, kwdefaults: dict[str, object] | None = None, ) -> Self: ... + else: def __new__( cls, @@ -1359,6 +1366,7 @@ class dict(MutableMapping[_KT, _VT]): def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... @overload def __ror__(self, value: frozendict[_T1, _T2], /) -> frozendict[_KT | _T1, _VT | _T2]: ... + else: def __or__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... @@ -2145,15 +2153,19 @@ def pow(base: _SupportsSomeKindOfPow, exp: complex, mod: None = None) -> complex quit: _sitebuiltins.Quitter +@type_check_only +class _SupportsReversed(Protocol[_T_co]): + def __reversed__(self) -> _T_co: ... + @disjoint_base -class reversed(Generic[_T]): +class reversed(Generic[_T_co]): @overload - def __new__(cls, sequence: Reversible[_T], /) -> Iterator[_T]: ... # type: ignore[misc] + def __new__(cls, sequence: _SupportsReversed[_T], /) -> _T: ... # type: ignore[misc] @overload - def __new__(cls, sequence: SupportsLenAndGetItem[_T], /) -> Iterator[_T]: ... # type: ignore[misc] + def __new__(cls, sequence: SupportsLenAndGetItem[_T_co], /) -> Self: ... def __iter__(self) -> Self: ... - def __next__(self) -> _T: ... + def __next__(self) -> _T_co: ... def __length_hint__(self) -> int: ... def repr(obj: object, /) -> str: ...