diff --git a/stdlib/_typeshed/__init__.pyi b/stdlib/_typeshed/__init__.pyi index 73b1f90541e6..ee3aa766d569 100644 --- a/stdlib/_typeshed/__init__.pyi +++ b/stdlib/_typeshed/__init__.pyi @@ -7,7 +7,7 @@ import ctypes import mmap import sys from os import PathLike -from typing import AbstractSet, Any, Container, Generic, Iterable, Protocol, TypeVar +from typing import AbstractSet, Any, Awaitable, Container, Generic, Iterable, Protocol, TypeVar from typing_extensions import Final, Literal, final _KT = TypeVar("_KT") @@ -33,7 +33,7 @@ class SupportsNext(Protocol[_T_co]): # stable class SupportsAnext(Protocol[_T_co]): - async def __anext__(self) -> _T_co: ... + def __anext__(self) -> Awaitable[_T_co]: ... # Comparison protocols diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index c668ca40e976..a347092e0122 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -29,6 +29,7 @@ from typing import ( IO, AbstractSet, Any, + Awaitable, BinaryIO, ByteString, Generic, @@ -72,6 +73,8 @@ _T4 = TypeVar("_T4") _T5 = TypeVar("_T5") _SupportsNextT = TypeVar("_SupportsNextT", bound=SupportsNext[Any], covariant=True) _SupportsAnextT = TypeVar("_SupportsAnextT", bound=SupportsAnext[Any], covariant=True) +_AwaitableT = TypeVar("_AwaitableT", bound=Awaitable[Any]) +_AwaitableT_co = TypeVar("_AwaitableT_co", bound=Awaitable[Any], covariant=True) class _SupportsIter(Protocol[_T_co]): def __iter__(self) -> _T_co: ... @@ -1068,8 +1071,15 @@ class _PathLike(Protocol[_AnyStr_co]): if sys.version_info >= (3, 10): def aiter(__async_iterable: _SupportsAiter[_SupportsAnextT]) -> _SupportsAnextT: ... + + class _SupportsSynchronousAnext(Protocol[_AwaitableT_co]): + def __anext__(self) -> _AwaitableT_co: ... + @overload - async def anext(__i: SupportsAnext[_T]) -> _T: ... + # `anext` is not, in fact, an async function. When default is not provided + # `anext` is just a passthrough for `obj.__anext__` + # See discussion in #7491 and pure-Python implementation of `anext` at https://github.com/python/cpython/blob/ea786a882b9ed4261eafabad6011bc7ef3b5bf94/Lib/test/test_asyncgen.py#L52-L80 + def anext(__i: _SupportsSynchronousAnext[_AwaitableT]) -> _AwaitableT: ... @overload async def anext(__i: SupportsAnext[_T], default: _VT) -> _T | _VT: ... diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 294fb2c0fc07..98792d3b48d7 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -154,7 +154,7 @@ class closing(AbstractContextManager[_SupportsCloseT]): if sys.version_info >= (3, 10): class _SupportsAclose(Protocol): - async def aclose(self) -> object: ... + def aclose(self) -> Awaitable[object]: ... _SupportsAcloseT = TypeVar("_SupportsAcloseT", bound=_SupportsAclose) class aclosing(AbstractAsyncContextManager[_SupportsAcloseT]): diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 457ad21b72d2..4766a416d9bb 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -743,26 +743,22 @@ class AsyncIterable(Protocol[_T_co]): @runtime_checkable class AsyncIterator(AsyncIterable[_T_co], Protocol[_T_co]): @abstractmethod - async def __anext__(self) -> _T_co: ... + def __anext__(self) -> Awaitable[_T_co]: ... def __aiter__(self) -> AsyncIterator[_T_co]: ... class AsyncGenerator(AsyncIterator[_T_co], Generic[_T_co, _T_contra]): + def __anext__(self) -> Awaitable[_T_co]: ... @abstractmethod - async def __anext__(self) -> _T_co: ... - @abstractmethod - async def asend(self, __value: _T_contra) -> _T_co: ... + def asend(self, __value: _T_contra) -> Awaitable[_T_co]: ... @overload @abstractmethod - async def athrow( + def athrow( self, __typ: Type[BaseException], __val: BaseException | object = ..., __tb: TracebackType | None = ... - ) -> _T_co: ... + ) -> Awaitable[_T_co]: ... @overload @abstractmethod - async def athrow(self, __typ: BaseException, __val: None = ..., __tb: TracebackType | None = ...) -> _T_co: ... - @abstractmethod - async def aclose(self) -> None: ... - @abstractmethod - def __aiter__(self) -> AsyncGenerator[_T_co, _T_contra]: ... + def athrow(self, __typ: BaseException, __val: None = ..., __tb: TracebackType | None = ...) -> Awaitable[_T_co]: ... + def aclose(self) -> Awaitable[None]: ... @property def ag_await(self) -> Any: ... @property diff --git a/tests/stubtest_allowlists/py310.txt b/tests/stubtest_allowlists/py310.txt index f59e0150fc9d..07c6b5338006 100644 --- a/tests/stubtest_allowlists/py310.txt +++ b/tests/stubtest_allowlists/py310.txt @@ -23,6 +23,7 @@ typing.IO.truncate typing.IO.write typing.IO.writelines +_collections_abc.AsyncGenerator.athrow # async at runtime, deliberately not in the stub, see #7491. Pos-only differences also. _weakref.ProxyType.__reversed__ # Doesn't really exist ast.Bytes.__new__ ast.Ellipsis.__new__ @@ -106,8 +107,6 @@ xml.etree.ElementTree.XMLParser.__init__ # Defined in C so has general signatur xml.etree.cElementTree.XMLParser.__init__ # Defined in C so has general signature # positional-only complaints caused by differences between typing aliases and the "real" classes in the stdlib -_collections_abc.AsyncGenerator.asend -_collections_abc.AsyncGenerator.athrow _collections_abc.Coroutine.send _collections_abc.Coroutine.throw _collections_abc.Generator.send diff --git a/tests/stubtest_allowlists/py36.txt b/tests/stubtest_allowlists/py36.txt index 201e0e05e69a..c7e4c5145ca2 100644 --- a/tests/stubtest_allowlists/py36.txt +++ b/tests/stubtest_allowlists/py36.txt @@ -11,6 +11,10 @@ asyncio.locks._ContextManagerMixin.__exit__ # Always raises; deliberately omitt builtins.float.__setformat__ # Internal method for CPython test suite builtins.str.maketrans cmath.log +collections.AsyncGenerator.asend # async at runtime, deliberately not in the stub, see #7491. Pos-only differences also. +collections.AsyncGenerator.__anext__ # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncGenerator.aclose # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncIterator.__anext__ # async at runtime, deliberately not in the stub, see #7491 collections.AsyncGenerator.ag_await collections.AsyncGenerator.ag_code collections.AsyncGenerator.ag_frame @@ -89,6 +93,8 @@ tkinter.filedialog.TkVersion tkinter.filedialog.wantobjects tkinter.simpledialog.wantobjects tkinter.tix.wantobjects +typing.AsyncGenerator.aclose # async at runtime, deliberately not in the stub, see #7491 +typing.AsyncGenerator.asend # async at runtime, deliberately not in the stub, see #7491 builtins.memoryview.__iter__ # C type that implements __getitem__ builtins.memoryview.cast # inspect.signature is incorrect about shape being kw-only diff --git a/tests/stubtest_allowlists/py37.txt b/tests/stubtest_allowlists/py37.txt index 9a9173c76f3e..207b1efd1d96 100644 --- a/tests/stubtest_allowlists/py37.txt +++ b/tests/stubtest_allowlists/py37.txt @@ -15,6 +15,10 @@ builtins.dict.get builtins.float.__set_format__ # Internal method for CPython test suite builtins.str.maketrans cmath.log +collections.AsyncGenerator.asend # async at runtime, deliberately not in the stub, see #7491. Pos-only differences also. +collections.AsyncGenerator.__anext__ # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncGenerator.aclose # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncIterator.__anext__ # async at runtime, deliberately not in the stub, see #7491 collections.AsyncGenerator.ag_await collections.AsyncGenerator.ag_code collections.AsyncGenerator.ag_frame diff --git a/tests/stubtest_allowlists/py38.txt b/tests/stubtest_allowlists/py38.txt index 34c7df60e9fa..f8466db95d3a 100644 --- a/tests/stubtest_allowlists/py38.txt +++ b/tests/stubtest_allowlists/py38.txt @@ -19,6 +19,10 @@ asyncio.locks._ContextManagerMixin.__enter__ # Always raises; deliberately omit asyncio.locks._ContextManagerMixin.__exit__ # Always raises; deliberately omitted from the stub builtins.dict.get builtins.float.__set_format__ # Internal method for CPython test suite +collections.AsyncGenerator.asend # async at runtime, deliberately not in the stub, see #7491. Pos-only differences also. +collections.AsyncGenerator.__anext__ # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncGenerator.aclose # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncIterator.__anext__ # async at runtime, deliberately not in the stub, see #7491 collections.AsyncGenerator.ag_await collections.AsyncGenerator.ag_code collections.AsyncGenerator.ag_frame diff --git a/tests/stubtest_allowlists/py39.txt b/tests/stubtest_allowlists/py39.txt index 6464c88c1732..e3510b9fbe8f 100644 --- a/tests/stubtest_allowlists/py39.txt +++ b/tests/stubtest_allowlists/py39.txt @@ -21,6 +21,10 @@ asyncio.futures.Future.__init__ # Usually initialized from c object asyncio.futures.Future._callbacks # Usually initialized from c object builtins.dict.get builtins.float.__set_format__ # Internal method for CPython test suite +collections.AsyncGenerator.asend # async at runtime, deliberately not in the stub, see #7491. Pos-only differences also. +collections.AsyncGenerator.__anext__ # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncGenerator.aclose # async at runtime, deliberately not in the stub, see #7491 +collections.AsyncIterator.__anext__ # async at runtime, deliberately not in the stub, see #7491 collections.AsyncGenerator.ag_await collections.AsyncGenerator.ag_code collections.AsyncGenerator.ag_frame diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index 13ac388e7bc5..bebd306bc803 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -246,6 +246,10 @@ xml.parsers.expat.expat_CAPI # ========== # Allowlist entries that cannot or should not be fixed # ========== +_collections_abc.AsyncGenerator.asend # async at runtime, deliberately not in the stub, see #7491. Pos-only differences also. +_collections_abc.AsyncGenerator.__anext__ # async at runtime, deliberately not in the stub, see #7491 +_collections_abc.AsyncGenerator.aclose # async at runtime, deliberately not in the stub, see #7491 +_collections_abc.AsyncIterator.__anext__ # async at runtime, deliberately not in the stub, see #7491 _pydecimal.* # See comments in file _weakref.ProxyType.__bytes__ # Doesn't really exist ast.NodeVisitor.visit_\w+ # Methods are discovered dynamically, see #3796