Skip to content

Commit f83b6fa

Browse files
authored
add _asyncio (#12766)
improves naming and inheritance for asyncio.Future and asyncio.Task related to #3968
1 parent 42ebc89 commit f83b6fa

File tree

6 files changed

+143
-111
lines changed

6 files changed

+143
-111
lines changed

stdlib/@tests/stubtest_allowlists/common.txt

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
# Please keep sorted alphabetically
66

7+
_asyncio.Future.__init__ # Usually initialized from c object
78
_collections_abc.AsyncGenerator.ag_await
89
_collections_abc.AsyncGenerator.ag_code
910
_collections_abc.AsyncGenerator.ag_frame

stdlib/VERSIONS

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
__future__: 3.0-
2121
__main__: 3.0-
2222
_ast: 3.0-
23+
_asyncio: 3.0-
2324
_bisect: 3.0-
2425
_bootlocale: 3.4-3.9
2526
_codecs: 3.0-

stdlib/_asyncio.pyi

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import sys
2+
from asyncio.events import AbstractEventLoop
3+
from collections.abc import Awaitable, Callable, Coroutine, Generator, Iterable
4+
from contextvars import Context
5+
from types import FrameType
6+
from typing import Any, Literal, TextIO, TypeVar
7+
from typing_extensions import Self, TypeAlias
8+
9+
if sys.version_info >= (3, 9):
10+
from types import GenericAlias
11+
12+
_T = TypeVar("_T")
13+
_T_co = TypeVar("_T_co", covariant=True)
14+
_TaskYieldType: TypeAlias = Future[object] | None
15+
16+
class Future(Awaitable[_T], Iterable[_T]):
17+
_state: str
18+
@property
19+
def _exception(self) -> BaseException | None: ...
20+
_blocking: bool
21+
@property
22+
def _log_traceback(self) -> bool: ...
23+
@_log_traceback.setter
24+
def _log_traceback(self, val: Literal[False]) -> None: ...
25+
_asyncio_future_blocking: bool # is a part of duck-typing contract for `Future`
26+
def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ...
27+
def __del__(self) -> None: ...
28+
def get_loop(self) -> AbstractEventLoop: ...
29+
@property
30+
def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ...
31+
def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ...
32+
if sys.version_info >= (3, 9):
33+
def cancel(self, msg: Any | None = None) -> bool: ...
34+
else:
35+
def cancel(self) -> bool: ...
36+
37+
def cancelled(self) -> bool: ...
38+
def done(self) -> bool: ...
39+
def result(self) -> _T: ...
40+
def exception(self) -> BaseException | None: ...
41+
def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ...
42+
def set_result(self, result: _T, /) -> None: ...
43+
def set_exception(self, exception: type | BaseException, /) -> None: ...
44+
def __iter__(self) -> Generator[Any, None, _T]: ...
45+
def __await__(self) -> Generator[Any, None, _T]: ...
46+
@property
47+
def _loop(self) -> AbstractEventLoop: ...
48+
if sys.version_info >= (3, 9):
49+
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
50+
51+
if sys.version_info >= (3, 12):
52+
_TaskCompatibleCoro: TypeAlias = Coroutine[Any, Any, _T_co]
53+
elif sys.version_info >= (3, 9):
54+
_TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Coroutine[Any, Any, _T_co]
55+
else:
56+
_TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co]
57+
58+
# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant.
59+
# While this is true in general, here it's sort-of okay to have a covariant subclass,
60+
# since the only reason why `asyncio.Future` is invariant is the `set_result()` method,
61+
# and `asyncio.Task.set_result()` always raises.
62+
class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments]
63+
if sys.version_info >= (3, 12):
64+
def __init__(
65+
self,
66+
coro: _TaskCompatibleCoro[_T_co],
67+
*,
68+
loop: AbstractEventLoop = ...,
69+
name: str | None = ...,
70+
context: Context | None = None,
71+
eager_start: bool = False,
72+
) -> None: ...
73+
elif sys.version_info >= (3, 11):
74+
def __init__(
75+
self,
76+
coro: _TaskCompatibleCoro[_T_co],
77+
*,
78+
loop: AbstractEventLoop = ...,
79+
name: str | None = ...,
80+
context: Context | None = None,
81+
) -> None: ...
82+
else:
83+
def __init__(
84+
self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ...
85+
) -> None: ...
86+
87+
if sys.version_info >= (3, 12):
88+
def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ...
89+
else:
90+
def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ...
91+
92+
def get_name(self) -> str: ...
93+
def set_name(self, value: object, /) -> None: ...
94+
if sys.version_info >= (3, 12):
95+
def get_context(self) -> Context: ...
96+
97+
def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ...
98+
def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ...
99+
if sys.version_info >= (3, 11):
100+
def cancelling(self) -> int: ...
101+
def uncancel(self) -> int: ...
102+
if sys.version_info < (3, 9):
103+
@classmethod
104+
def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
105+
@classmethod
106+
def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...
107+
if sys.version_info >= (3, 9):
108+
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
109+
110+
def get_event_loop() -> AbstractEventLoop: ...
111+
def get_running_loop() -> AbstractEventLoop: ...
112+
def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ...
113+
def _get_running_loop() -> AbstractEventLoop: ...
114+
def _register_task(task: Task[Any]) -> None: ...
115+
def _unregister_task(task: Task[Any]) -> None: ...
116+
def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
117+
def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
118+
119+
if sys.version_info >= (3, 12):
120+
def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...

stdlib/asyncio/events.pyi

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import ssl
22
import sys
3+
from _asyncio import (
4+
_get_running_loop as _get_running_loop,
5+
_set_running_loop as _set_running_loop,
6+
get_event_loop as get_event_loop,
7+
get_running_loop as get_running_loop,
8+
)
39
from _typeshed import FileDescriptorLike, ReadableBuffer, StrPath, Unused, WriteableBuffer
410
from abc import ABCMeta, abstractmethod
511
from collections.abc import Callable, Sequence
@@ -632,7 +638,6 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy, metaclass=ABCMeta):
632638

633639
def get_event_loop_policy() -> AbstractEventLoopPolicy: ...
634640
def set_event_loop_policy(policy: AbstractEventLoopPolicy | None) -> None: ...
635-
def get_event_loop() -> AbstractEventLoop: ...
636641
def set_event_loop(loop: AbstractEventLoop | None) -> None: ...
637642
def new_event_loop() -> AbstractEventLoop: ...
638643

@@ -646,7 +651,3 @@ if sys.version_info < (3, 14):
646651
else:
647652
def get_child_watcher() -> AbstractChildWatcher: ...
648653
def set_child_watcher(watcher: AbstractChildWatcher) -> None: ...
649-
650-
def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ...
651-
def _get_running_loop() -> AbstractEventLoop: ...
652-
def get_running_loop() -> AbstractEventLoop: ...

stdlib/asyncio/futures.pyi

+3-44
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
import sys
2-
from collections.abc import Awaitable, Callable, Generator, Iterable
1+
from _asyncio import Future as Future
32
from concurrent.futures._base import Future as _ConcurrentFuture
4-
from contextvars import Context
5-
from typing import Any, Literal, TypeVar
6-
from typing_extensions import Self, TypeIs
3+
from typing import Any, TypeVar
4+
from typing_extensions import TypeIs
75

86
from .events import AbstractEventLoop
97

10-
if sys.version_info >= (3, 9):
11-
from types import GenericAlias
12-
138
__all__ = ("Future", "wrap_future", "isfuture")
149

1510
_T = TypeVar("_T")
@@ -18,40 +13,4 @@ _T = TypeVar("_T")
1813
# but it leads to circular import error in pytype tool.
1914
# That's why the import order is reversed.
2015
def isfuture(obj: object) -> TypeIs[Future[Any]]: ...
21-
22-
class Future(Awaitable[_T], Iterable[_T]):
23-
_state: str
24-
@property
25-
def _exception(self) -> BaseException | None: ...
26-
_blocking: bool
27-
@property
28-
def _log_traceback(self) -> bool: ...
29-
@_log_traceback.setter
30-
def _log_traceback(self, val: Literal[False]) -> None: ...
31-
_asyncio_future_blocking: bool # is a part of duck-typing contract for `Future`
32-
def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ...
33-
def __del__(self) -> None: ...
34-
def get_loop(self) -> AbstractEventLoop: ...
35-
@property
36-
def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ...
37-
def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ...
38-
if sys.version_info >= (3, 9):
39-
def cancel(self, msg: Any | None = None) -> bool: ...
40-
else:
41-
def cancel(self) -> bool: ...
42-
43-
def cancelled(self) -> bool: ...
44-
def done(self) -> bool: ...
45-
def result(self) -> _T: ...
46-
def exception(self) -> BaseException | None: ...
47-
def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ...
48-
def set_result(self, result: _T, /) -> None: ...
49-
def set_exception(self, exception: type | BaseException, /) -> None: ...
50-
def __iter__(self) -> Generator[Any, None, _T]: ...
51-
def __await__(self) -> Generator[Any, None, _T]: ...
52-
@property
53-
def _loop(self) -> AbstractEventLoop: ...
54-
if sys.version_info >= (3, 9):
55-
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
56-
5716
def wrap_future(future: _ConcurrentFuture[_T] | Future[_T], *, loop: AbstractEventLoop | None = None) -> Future[_T]: ...

stdlib/asyncio/tasks.pyi

+12-62
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import concurrent.futures
22
import sys
3+
from _asyncio import (
4+
Task as Task,
5+
_enter_task as _enter_task,
6+
_leave_task as _leave_task,
7+
_register_task as _register_task,
8+
_unregister_task as _unregister_task,
9+
)
310
from collections.abc import Awaitable, Coroutine, Generator, Iterable, Iterator
4-
from types import FrameType
5-
from typing import Any, Literal, Protocol, TextIO, TypeVar, overload
11+
from typing import Any, Literal, Protocol, TypeVar, overload
612
from typing_extensions import TypeAlias
713

814
from . import _CoroutineLike
915
from .events import AbstractEventLoop
1016
from .futures import Future
1117

12-
if sys.version_info >= (3, 9):
13-
from types import GenericAlias
1418
if sys.version_info >= (3, 11):
1519
from contextvars import Context
1620

@@ -400,58 +404,6 @@ elif sys.version_info >= (3, 9):
400404
else:
401405
_TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co]
402406

403-
# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant.
404-
# While this is true in general, here it's sort-of okay to have a covariant subclass,
405-
# since the only reason why `asyncio.Future` is invariant is the `set_result()` method,
406-
# and `asyncio.Task.set_result()` always raises.
407-
class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments]
408-
if sys.version_info >= (3, 12):
409-
def __init__(
410-
self,
411-
coro: _TaskCompatibleCoro[_T_co],
412-
*,
413-
loop: AbstractEventLoop = ...,
414-
name: str | None = ...,
415-
context: Context | None = None,
416-
eager_start: bool = False,
417-
) -> None: ...
418-
elif sys.version_info >= (3, 11):
419-
def __init__(
420-
self,
421-
coro: _TaskCompatibleCoro[_T_co],
422-
*,
423-
loop: AbstractEventLoop = ...,
424-
name: str | None = ...,
425-
context: Context | None = None,
426-
) -> None: ...
427-
else:
428-
def __init__(
429-
self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ...
430-
) -> None: ...
431-
432-
if sys.version_info >= (3, 12):
433-
def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ...
434-
else:
435-
def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ...
436-
437-
def get_name(self) -> str: ...
438-
def set_name(self, value: object, /) -> None: ...
439-
if sys.version_info >= (3, 12):
440-
def get_context(self) -> Context: ...
441-
442-
def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ...
443-
def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ...
444-
if sys.version_info >= (3, 11):
445-
def cancelling(self) -> int: ...
446-
def uncancel(self) -> int: ...
447-
if sys.version_info < (3, 9):
448-
@classmethod
449-
def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
450-
@classmethod
451-
def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...
452-
if sys.version_info >= (3, 9):
453-
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
454-
455407
def all_tasks(loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...
456408

457409
if sys.version_info >= (3, 11):
@@ -460,9 +412,10 @@ if sys.version_info >= (3, 11):
460412
else:
461413
def create_task(coro: _CoroutineLike[_T], *, name: str | None = None) -> Task[_T]: ...
462414

463-
def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
464-
def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
465-
def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
415+
if sys.version_info >= (3, 12):
416+
from _asyncio import current_task as current_task
417+
else:
418+
def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
466419

467420
if sys.version_info >= (3, 12):
468421
_TaskT_co = TypeVar("_TaskT_co", bound=Task[Any], covariant=True)
@@ -499,6 +452,3 @@ if sys.version_info >= (3, 12):
499452
name: str | None = None,
500453
context: Context | None = None,
501454
) -> Task[_T_co]: ...
502-
503-
def _register_task(task: Task[Any]) -> None: ...
504-
def _unregister_task(task: Task[Any]) -> None: ...

0 commit comments

Comments
 (0)