diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index d3b998c61590..36b7bf39b6c9 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -4,6 +4,7 @@ # Please keep sorted alphabetically +_asyncio.Future.__init__ # Usually initialized from c object _collections_abc.AsyncGenerator.ag_await _collections_abc.AsyncGenerator.ag_code _collections_abc.AsyncGenerator.ag_frame diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index 28a27f5d9a0b..ed23ee6ddcea 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -20,6 +20,7 @@ __future__: 3.0- __main__: 3.0- _ast: 3.0- +_asyncio: 3.0- _bisect: 3.0- _bootlocale: 3.4-3.9 _codecs: 3.0- diff --git a/stdlib/_asyncio.pyi b/stdlib/_asyncio.pyi new file mode 100644 index 000000000000..18920cd8a8a4 --- /dev/null +++ b/stdlib/_asyncio.pyi @@ -0,0 +1,120 @@ +import sys +from asyncio.events import AbstractEventLoop +from collections.abc import Awaitable, Callable, Coroutine, Generator, Iterable +from contextvars import Context +from types import FrameType +from typing import Any, Literal, TextIO, TypeVar +from typing_extensions import Self, TypeAlias + +if sys.version_info >= (3, 9): + from types import GenericAlias + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) +_TaskYieldType: TypeAlias = Future[object] | None + +class Future(Awaitable[_T], Iterable[_T]): + _state: str + @property + def _exception(self) -> BaseException | None: ... + _blocking: bool + @property + def _log_traceback(self) -> bool: ... + @_log_traceback.setter + def _log_traceback(self, val: Literal[False]) -> None: ... + _asyncio_future_blocking: bool # is a part of duck-typing contract for `Future` + def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ... + def __del__(self) -> None: ... + def get_loop(self) -> AbstractEventLoop: ... + @property + def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ... + def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ... + if sys.version_info >= (3, 9): + def cancel(self, msg: Any | None = None) -> bool: ... + else: + def cancel(self) -> bool: ... + + def cancelled(self) -> bool: ... + def done(self) -> bool: ... + def result(self) -> _T: ... + def exception(self) -> BaseException | None: ... + def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ... + def set_result(self, result: _T, /) -> None: ... + def set_exception(self, exception: type | BaseException, /) -> None: ... + def __iter__(self) -> Generator[Any, None, _T]: ... + def __await__(self) -> Generator[Any, None, _T]: ... + @property + def _loop(self) -> AbstractEventLoop: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +if sys.version_info >= (3, 12): + _TaskCompatibleCoro: TypeAlias = Coroutine[Any, Any, _T_co] +elif sys.version_info >= (3, 9): + _TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Coroutine[Any, Any, _T_co] +else: + _TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co] + +# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant. +# While this is true in general, here it's sort-of okay to have a covariant subclass, +# since the only reason why `asyncio.Future` is invariant is the `set_result()` method, +# and `asyncio.Task.set_result()` always raises. +class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] + if sys.version_info >= (3, 12): + def __init__( + self, + coro: _TaskCompatibleCoro[_T_co], + *, + loop: AbstractEventLoop = ..., + name: str | None = ..., + context: Context | None = None, + eager_start: bool = False, + ) -> None: ... + elif sys.version_info >= (3, 11): + def __init__( + self, + coro: _TaskCompatibleCoro[_T_co], + *, + loop: AbstractEventLoop = ..., + name: str | None = ..., + context: Context | None = None, + ) -> None: ... + else: + def __init__( + self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ... + ) -> None: ... + + if sys.version_info >= (3, 12): + def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ... + else: + def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ... + + def get_name(self) -> str: ... + def set_name(self, value: object, /) -> None: ... + if sys.version_info >= (3, 12): + def get_context(self) -> Context: ... + + def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ... + def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ... + if sys.version_info >= (3, 11): + def cancelling(self) -> int: ... + def uncancel(self) -> int: ... + if sys.version_info < (3, 9): + @classmethod + def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... + @classmethod + def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +def get_event_loop() -> AbstractEventLoop: ... +def get_running_loop() -> AbstractEventLoop: ... +def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ... +def _get_running_loop() -> AbstractEventLoop: ... +def _register_task(task: Task[Any]) -> None: ... +def _unregister_task(task: Task[Any]) -> None: ... +def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... +def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... + +if sys.version_info >= (3, 12): + def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... diff --git a/stdlib/asyncio/events.pyi b/stdlib/asyncio/events.pyi index eed688fc792a..ead64070671f 100644 --- a/stdlib/asyncio/events.pyi +++ b/stdlib/asyncio/events.pyi @@ -1,5 +1,11 @@ import ssl import sys +from _asyncio import ( + _get_running_loop as _get_running_loop, + _set_running_loop as _set_running_loop, + get_event_loop as get_event_loop, + get_running_loop as get_running_loop, +) from _typeshed import FileDescriptorLike, ReadableBuffer, StrPath, Unused, WriteableBuffer from abc import ABCMeta, abstractmethod from collections.abc import Callable, Sequence @@ -632,7 +638,6 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy, metaclass=ABCMeta): def get_event_loop_policy() -> AbstractEventLoopPolicy: ... def set_event_loop_policy(policy: AbstractEventLoopPolicy | None) -> None: ... -def get_event_loop() -> AbstractEventLoop: ... def set_event_loop(loop: AbstractEventLoop | None) -> None: ... def new_event_loop() -> AbstractEventLoop: ... @@ -646,7 +651,3 @@ if sys.version_info < (3, 14): else: def get_child_watcher() -> AbstractChildWatcher: ... def set_child_watcher(watcher: AbstractChildWatcher) -> None: ... - -def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ... -def _get_running_loop() -> AbstractEventLoop: ... -def get_running_loop() -> AbstractEventLoop: ... diff --git a/stdlib/asyncio/futures.pyi b/stdlib/asyncio/futures.pyi index e19fd53f3311..28e6ca8c86a3 100644 --- a/stdlib/asyncio/futures.pyi +++ b/stdlib/asyncio/futures.pyi @@ -1,15 +1,10 @@ -import sys -from collections.abc import Awaitable, Callable, Generator, Iterable +from _asyncio import Future as Future from concurrent.futures._base import Future as _ConcurrentFuture -from contextvars import Context -from typing import Any, Literal, TypeVar -from typing_extensions import Self, TypeIs +from typing import Any, TypeVar +from typing_extensions import TypeIs from .events import AbstractEventLoop -if sys.version_info >= (3, 9): - from types import GenericAlias - __all__ = ("Future", "wrap_future", "isfuture") _T = TypeVar("_T") @@ -18,40 +13,4 @@ _T = TypeVar("_T") # but it leads to circular import error in pytype tool. # That's why the import order is reversed. def isfuture(obj: object) -> TypeIs[Future[Any]]: ... - -class Future(Awaitable[_T], Iterable[_T]): - _state: str - @property - def _exception(self) -> BaseException | None: ... - _blocking: bool - @property - def _log_traceback(self) -> bool: ... - @_log_traceback.setter - def _log_traceback(self, val: Literal[False]) -> None: ... - _asyncio_future_blocking: bool # is a part of duck-typing contract for `Future` - def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ... - def __del__(self) -> None: ... - def get_loop(self) -> AbstractEventLoop: ... - @property - def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ... - def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ... - if sys.version_info >= (3, 9): - def cancel(self, msg: Any | None = None) -> bool: ... - else: - def cancel(self) -> bool: ... - - def cancelled(self) -> bool: ... - def done(self) -> bool: ... - def result(self) -> _T: ... - def exception(self) -> BaseException | None: ... - def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ... - def set_result(self, result: _T, /) -> None: ... - def set_exception(self, exception: type | BaseException, /) -> None: ... - def __iter__(self) -> Generator[Any, None, _T]: ... - def __await__(self) -> Generator[Any, None, _T]: ... - @property - def _loop(self) -> AbstractEventLoop: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - def wrap_future(future: _ConcurrentFuture[_T] | Future[_T], *, loop: AbstractEventLoop | None = None) -> Future[_T]: ... diff --git a/stdlib/asyncio/tasks.pyi b/stdlib/asyncio/tasks.pyi index bb423e857399..47d1bb13e4a3 100644 --- a/stdlib/asyncio/tasks.pyi +++ b/stdlib/asyncio/tasks.pyi @@ -1,16 +1,20 @@ import concurrent.futures import sys +from _asyncio import ( + Task as Task, + _enter_task as _enter_task, + _leave_task as _leave_task, + _register_task as _register_task, + _unregister_task as _unregister_task, +) from collections.abc import Awaitable, Coroutine, Generator, Iterable, Iterator -from types import FrameType -from typing import Any, Literal, Protocol, TextIO, TypeVar, overload +from typing import Any, Literal, Protocol, TypeVar, overload from typing_extensions import TypeAlias from . import _CoroutineLike from .events import AbstractEventLoop from .futures import Future -if sys.version_info >= (3, 9): - from types import GenericAlias if sys.version_info >= (3, 11): from contextvars import Context @@ -400,58 +404,6 @@ elif sys.version_info >= (3, 9): else: _TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co] -# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant. -# While this is true in general, here it's sort-of okay to have a covariant subclass, -# since the only reason why `asyncio.Future` is invariant is the `set_result()` method, -# and `asyncio.Task.set_result()` always raises. -class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] - if sys.version_info >= (3, 12): - def __init__( - self, - coro: _TaskCompatibleCoro[_T_co], - *, - loop: AbstractEventLoop = ..., - name: str | None = ..., - context: Context | None = None, - eager_start: bool = False, - ) -> None: ... - elif sys.version_info >= (3, 11): - def __init__( - self, - coro: _TaskCompatibleCoro[_T_co], - *, - loop: AbstractEventLoop = ..., - name: str | None = ..., - context: Context | None = None, - ) -> None: ... - else: - def __init__( - self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ... - ) -> None: ... - - if sys.version_info >= (3, 12): - def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ... - else: - def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ... - - def get_name(self) -> str: ... - def set_name(self, value: object, /) -> None: ... - if sys.version_info >= (3, 12): - def get_context(self) -> Context: ... - - def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ... - def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ... - if sys.version_info >= (3, 11): - def cancelling(self) -> int: ... - def uncancel(self) -> int: ... - if sys.version_info < (3, 9): - @classmethod - def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... - @classmethod - def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - def all_tasks(loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ... if sys.version_info >= (3, 11): @@ -460,9 +412,10 @@ if sys.version_info >= (3, 11): else: def create_task(coro: _CoroutineLike[_T], *, name: str | None = None) -> Task[_T]: ... -def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... -def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... -def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... +if sys.version_info >= (3, 12): + from _asyncio import current_task as current_task +else: + def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... if sys.version_info >= (3, 12): _TaskT_co = TypeVar("_TaskT_co", bound=Task[Any], covariant=True) @@ -499,6 +452,3 @@ if sys.version_info >= (3, 12): name: str | None = None, context: Context | None = None, ) -> Task[_T_co]: ... - -def _register_task(task: Task[Any]) -> None: ... -def _unregister_task(task: Task[Any]) -> None: ...