Fix asyncio.gather regression (#8271)

Adding the empty-tuple overload caused major problems for pyright, and that overload only deals with an unlikely edge case anyway. Get rid of it, and replace the fallback overload with a more general overload.

Fixes #8270.
This commit is contained in:
Alex Waygood
2022-07-16 18:56:58 +01:00
committed by GitHub
parent de1a79bd00
commit 1ebe1b463e
2 changed files with 58 additions and 44 deletions

View File

@@ -66,17 +66,18 @@ def ensure_future(coro_or_future: Awaitable[_T], *, loop: AbstractEventLoop | No
# of tasks passed; however, Tuple is used similar to the annotation for
# zip() because typing does not support variadic type variables. See
# typing PR #1550 for discussion.
#
# The many type: ignores here are because the overloads overlap,
# but having overlapping overloads is the only way to get acceptable type inference in all edge cases.
if sys.version_info >= (3, 10):
@overload
def gather(*, return_exceptions: bool = ...) -> Future[tuple[()]]: ...
def gather(__coro_or_future1: _FutureLike[_T1], *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]: ... # type: ignore[misc]
@overload
def gather(__coro_or_future1: _FutureLike[_T1], *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1], __coro_or_future2: _FutureLike[_T2], *, return_exceptions: Literal[False] = ...
) -> Future[tuple[_T1, _T2]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -84,7 +85,7 @@ if sys.version_info >= (3, 10):
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2, _T3]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -93,7 +94,7 @@ if sys.version_info >= (3, 10):
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2, _T3, _T4]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -103,13 +104,13 @@ if sys.version_info >= (3, 10):
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]: ...
@overload
def gather(__coro_or_future1: _FutureLike[_T1], *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException]]: ...
def gather(__coro_or_future1: _FutureLike[_T1], *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException]]: ... # type: ignore[misc]
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1], __coro_or_future2: _FutureLike[_T2], *, return_exceptions: bool
) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -117,7 +118,7 @@ if sys.version_info >= (3, 10):
return_exceptions: bool,
) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -126,7 +127,7 @@ if sys.version_info >= (3, 10):
return_exceptions: bool,
) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -138,26 +139,15 @@ if sys.version_info >= (3, 10):
tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException]
]: ...
@overload
def gather(
__coro_or_future1: _FutureLike[Any],
__coro_or_future2: _FutureLike[Any],
__coro_or_future3: _FutureLike[Any],
__coro_or_future4: _FutureLike[Any],
__coro_or_future5: _FutureLike[Any],
__coro_or_future6: _FutureLike[Any],
*coros_or_futures: _FutureLike[Any],
return_exceptions: bool = ...,
) -> Future[list[Any]]: ...
def gather(*coros_or_futures: _FutureLike[Any], return_exceptions: bool = ...) -> Future[list[Any]]: ... # type: ignore[misc]
else:
@overload
def gather(*, loop: AbstractEventLoop | None = ..., return_exceptions: bool = ...) -> Future[tuple[()]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1], *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ...
) -> Future[tuple[_T1]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
*,
@@ -165,7 +155,7 @@ else:
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -174,7 +164,7 @@ else:
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2, _T3]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -184,7 +174,7 @@ else:
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2, _T3, _T4]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -195,11 +185,11 @@ else:
return_exceptions: Literal[False] = ...,
) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1], *, loop: AbstractEventLoop | None = ..., return_exceptions: bool
) -> Future[tuple[_T1 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
*,
@@ -207,7 +197,7 @@ else:
return_exceptions: bool,
) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -216,7 +206,7 @@ else:
return_exceptions: bool,
) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -226,7 +216,7 @@ else:
return_exceptions: bool,
) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ...
@overload
def gather(
def gather( # type: ignore[misc]
__coro_or_future1: _FutureLike[_T1],
__coro_or_future2: _FutureLike[_T2],
__coro_or_future3: _FutureLike[_T3],
@@ -239,16 +229,8 @@ else:
tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException]
]: ...
@overload
def gather(
__coro_or_future1: _FutureLike[Any],
__coro_or_future2: _FutureLike[Any],
__coro_or_future3: _FutureLike[Any],
__coro_or_future4: _FutureLike[Any],
__coro_or_future5: _FutureLike[Any],
__coro_or_future6: _FutureLike[Any],
*coros_or_futures: _FutureLike[Any],
loop: AbstractEventLoop | None = ...,
return_exceptions: bool = ...,
def gather( # type: ignore[misc]
*coros_or_futures: _FutureLike[Any], loop: AbstractEventLoop | None = ..., return_exceptions: bool = ...
) -> Future[list[Any]]: ...
def run_coroutine_threadsafe(coro: _FutureLike[_T], loop: AbstractEventLoop) -> concurrent.futures.Future[_T]: ...

View File

@@ -0,0 +1,32 @@
import asyncio
from typing import Any, Awaitable, List, Tuple, Union
from typing_extensions import assert_type
async def coro1() -> int:
return 42
async def coro2() -> str:
return "spam"
async def test_gather(awaitable1: Awaitable[int], awaitable2: Awaitable[str]) -> None:
a = await asyncio.gather(awaitable1)
assert_type(a, Tuple[int])
b = await asyncio.gather(awaitable1, awaitable2, return_exceptions=True)
assert_type(b, Tuple[Union[int, BaseException], Union[str, BaseException]])
c = await asyncio.gather(awaitable1, awaitable2, awaitable1, awaitable1, awaitable1, awaitable1)
assert_type(c, List[Any])
awaitables_list: List[Awaitable[int]] = [awaitable1]
d = await asyncio.gather(*awaitables_list)
assert_type(d, List[Any])
e = await asyncio.gather()
assert_type(e, List[Any])
asyncio.run(test_gather(coro1(), coro2()))