Skip to content

Commit 384fcbd

Browse files
committed
Preserve Task types in as_completed
1 parent a767999 commit 384fcbd

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import sys
5+
from collections.abc import Coroutine
6+
from typing import Any
7+
from typing_extensions import assert_type
8+
9+
10+
async def result() -> int:
11+
return 42
12+
13+
14+
if sys.version_info >= (3, 13):
15+
16+
async def check_as_completed() -> None:
17+
task = asyncio.create_task(result())
18+
19+
async for completed_task in asyncio.as_completed([task]):
20+
assert_type(completed_task, asyncio.Task[int])
21+
completed_task.cancelling()
22+
23+
coroutine_for_async_iteration = result()
24+
async for completed_future in asyncio.as_completed([coroutine_for_async_iteration]):
25+
assert_type(completed_future, asyncio.Future[int])
26+
27+
for completed_coroutine in asyncio.as_completed([task]):
28+
coroutine: Coroutine[Any, Any, int] = completed_coroutine
29+
assert_type(await coroutine, int)

‎stdlib/asyncio/tasks.pyi‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ else:
6767

6868
_T = TypeVar("_T")
6969
_T_co = TypeVar("_T_co", covariant=True)
70+
_T_sync_co = TypeVar("_T_sync_co", covariant=True)
71+
_T_async_co = TypeVar("_T_async_co", covariant=True)
7072
_T1 = TypeVar("_T1")
7173
_T2 = TypeVar("_T2")
7274
_T3 = TypeVar("_T3")
@@ -87,9 +89,16 @@ ALL_COMPLETED: Final = concurrent.futures.ALL_COMPLETED
8789

8890
if sys.version_info >= (3, 13):
8991
@type_check_only
90-
class _SyncAndAsyncIterator(Iterator[Coroutine[Any, Any, _T]], AsyncIterator[Future[_T]], Protocol[_T]): ...
92+
class _SyncAndAsyncIterator(Iterator[_T_sync_co], AsyncIterator[_T_async_co], Protocol[_T_sync_co, _T_async_co]): ...
9193

92-
def as_completed(fs: Iterable[_FutureLike[_T]], *, timeout: float | None = None) -> _SyncAndAsyncIterator[_T]: ...
94+
@overload
95+
def as_completed(
96+
fs: Iterable[Task[_T]], *, timeout: float | None = None
97+
) -> _SyncAndAsyncIterator[Coroutine[Any, Any, _T], Task[_T]]: ...
98+
@overload
99+
def as_completed(
100+
fs: Iterable[_FutureLike[_T]], *, timeout: float | None = None
101+
) -> _SyncAndAsyncIterator[Coroutine[Any, Any, _T], Future[_T]]: ...
93102

94103
else:
95104
def as_completed(fs: Iterable[_FutureLike[_T]], *, timeout: float | None = None) -> Iterator[Future[_T]]: ...

0 commit comments

Comments
 (0)