From c79730e9ee903a3ac93f96b995ce41d1bef1de70 Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 15 Jun 2022 17:19:45 +0100 Subject: [PATCH 1/4] added support for arbitary length *args with variadic generic --- stdlib/asyncio/tasks.pyi | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/stdlib/asyncio/tasks.pyi b/stdlib/asyncio/tasks.pyi index d7119b0400ba..059089eab6c4 100644 --- a/stdlib/asyncio/tasks.pyi +++ b/stdlib/asyncio/tasks.pyi @@ -12,6 +12,8 @@ if sys.version_info >= (3, 9): from types import GenericAlias if sys.version_info >= (3, 11): from contextvars import Context + from typing_extensions import TypeVarTuple, Unpack + if sys.version_info >= (3, 7): __all__ = ( @@ -65,6 +67,9 @@ FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION ALL_COMPLETED = concurrent.futures.ALL_COMPLETED +if sys.version_info >= (3, 11): + _Ts = TypeVarTuple("_Ts") + if sys.version_info >= (3, 10): def as_completed(fs: Iterable[_FutureT[_T]], *, timeout: float | None = ...) -> Iterator[Future[_T]]: ... @@ -81,10 +86,13 @@ def ensure_future(coro_or_future: Awaitable[_T], *, loop: AbstractEventLoop | No # Prior to Python 3.7 'async' was an alias for 'ensure_future'. # It became a keyword in 3.7. +if sys.version_info >= (3, 11): + def gather( + *__coro_or_future: Unpack[_Ts[_FutureT[_T]]], return_exceptions: Literal[False] = ... + ) -> Future[tuple[Unpack[_Ts[_T1]]]]: ... # `gather()` actually returns a list with length equal to the number -# 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. +# of tasks passed; however, Variadic Generics (PEP 646) is only supported +# in Python 3.11 and above, so a tuple is used similar to zip(). if sys.version_info >= (3, 10): @overload def gather(__coro_or_future1: _FutureT[_T1], *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]: ... From efb64210e817fcf9f7abfd7623e33aee0c31d160 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 15 Jun 2022 16:23:40 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/asyncio/tasks.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/asyncio/tasks.pyi b/stdlib/asyncio/tasks.pyi index 059089eab6c4..1ad182433424 100644 --- a/stdlib/asyncio/tasks.pyi +++ b/stdlib/asyncio/tasks.pyi @@ -14,7 +14,6 @@ if sys.version_info >= (3, 11): from contextvars import Context from typing_extensions import TypeVarTuple, Unpack - if sys.version_info >= (3, 7): __all__ = ( "Task", @@ -90,6 +89,7 @@ if sys.version_info >= (3, 11): def gather( *__coro_or_future: Unpack[_Ts[_FutureT[_T]]], return_exceptions: Literal[False] = ... ) -> Future[tuple[Unpack[_Ts[_T1]]]]: ... + # `gather()` actually returns a list with length equal to the number # of tasks passed; however, Variadic Generics (PEP 646) is only supported # in Python 3.11 and above, so a tuple is used similar to zip(). From 817cddc7a77d2aa0019cb8072d69e23cc3ff8878 Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 15 Jun 2022 19:09:16 +0100 Subject: [PATCH 3/4] changed imports to typing_extensions to ensure compatibility with all Python versions --- stdlib/asyncio/tasks.pyi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stdlib/asyncio/tasks.pyi b/stdlib/asyncio/tasks.pyi index 1ad182433424..7ae67a55b602 100644 --- a/stdlib/asyncio/tasks.pyi +++ b/stdlib/asyncio/tasks.pyi @@ -3,7 +3,7 @@ import sys from collections.abc import Awaitable, Coroutine, Generator, Iterable, Iterator from types import FrameType from typing import Any, Generic, TextIO, TypeVar, overload -from typing_extensions import Literal, TypeAlias +from typing_extensions import Literal, TypeAlias, TypeVarTuple, Unpack from .events import AbstractEventLoop from .futures import Future @@ -59,6 +59,7 @@ _T3 = TypeVar("_T3") _T4 = TypeVar("_T4") _T5 = TypeVar("_T5") _FT = TypeVar("_FT", bound=Future[Any]) +_Ts = TypeVarTuple("_Ts") _FutureT: TypeAlias = Future[_T] | Generator[Any, None, _T] | Awaitable[_T] _TaskYieldType: TypeAlias = Future[object] | None @@ -66,9 +67,6 @@ FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION ALL_COMPLETED = concurrent.futures.ALL_COMPLETED -if sys.version_info >= (3, 11): - _Ts = TypeVarTuple("_Ts") - if sys.version_info >= (3, 10): def as_completed(fs: Iterable[_FutureT[_T]], *, timeout: float | None = ...) -> Iterator[Future[_T]]: ... From 0e962d4ec3523da2bd9b3a1f04fca93dc5e25d30 Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 15 Jun 2022 19:13:13 +0100 Subject: [PATCH 4/4] removed redundant type annotations for individual Python versions --- stdlib/asyncio/tasks.pyi | 193 +-------------------------------------- 1 file changed, 3 insertions(+), 190 deletions(-) diff --git a/stdlib/asyncio/tasks.pyi b/stdlib/asyncio/tasks.pyi index 7ae67a55b602..25e4d57a25c7 100644 --- a/stdlib/asyncio/tasks.pyi +++ b/stdlib/asyncio/tasks.pyi @@ -12,7 +12,6 @@ if sys.version_info >= (3, 9): from types import GenericAlias if sys.version_info >= (3, 11): from contextvars import Context - from typing_extensions import TypeVarTuple, Unpack if sys.version_info >= (3, 7): __all__ = ( @@ -83,195 +82,9 @@ def ensure_future(coro_or_future: Awaitable[_T], *, loop: AbstractEventLoop | No # Prior to Python 3.7 'async' was an alias for 'ensure_future'. # It became a keyword in 3.7. -if sys.version_info >= (3, 11): - def gather( - *__coro_or_future: Unpack[_Ts[_FutureT[_T]]], return_exceptions: Literal[False] = ... - ) -> Future[tuple[Unpack[_Ts[_T1]]]]: ... - -# `gather()` actually returns a list with length equal to the number -# of tasks passed; however, Variadic Generics (PEP 646) is only supported -# in Python 3.11 and above, so a tuple is used similar to zip(). -if sys.version_info >= (3, 10): - @overload - def gather(__coro_or_future1: _FutureT[_T1], *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], __coro_or_future2: _FutureT[_T2], *, return_exceptions: Literal[False] = ... - ) -> Future[tuple[_T1, _T2]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - *, - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2, _T3]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - *, - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2, _T3, _T4]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - __coro_or_future5: _FutureT[_T5], - *, - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[Any], - __coro_or_future2: _FutureT[Any], - __coro_or_future3: _FutureT[Any], - __coro_or_future4: _FutureT[Any], - __coro_or_future5: _FutureT[Any], - __coro_or_future6: _FutureT[Any], - *coros_or_futures: _FutureT[Any], - return_exceptions: bool = ..., - ) -> Future[list[Any]]: ... - @overload - def gather(__coro_or_future1: _FutureT[_T1], *, return_exceptions: bool = ...) -> Future[tuple[_T1 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], __coro_or_future2: _FutureT[_T2], *, return_exceptions: bool = ... - ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - *, - return_exceptions: bool = ..., - ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - *, - return_exceptions: bool = ..., - ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - __coro_or_future5: _FutureT[_T5], - *, - return_exceptions: bool = ..., - ) -> Future[ - tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException] - ]: ... - -else: - @overload - def gather( - __coro_or_future1: _FutureT[_T1], *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ... - ) -> Future[tuple[_T1]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2, _T3]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2, _T3, _T4]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - __coro_or_future5: _FutureT[_T5], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: Literal[False] = ..., - ) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[Any], - __coro_or_future2: _FutureT[Any], - __coro_or_future3: _FutureT[Any], - __coro_or_future4: _FutureT[Any], - __coro_or_future5: _FutureT[Any], - __coro_or_future6: _FutureT[Any], - *coros_or_futures: _FutureT[Any], - loop: AbstractEventLoop | None = ..., - return_exceptions: bool = ..., - ) -> Future[list[Any]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], *, loop: AbstractEventLoop | None = ..., return_exceptions: bool = ... - ) -> Future[tuple[_T1 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: bool = ..., - ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: bool = ..., - ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: bool = ..., - ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ... - @overload - def gather( - __coro_or_future1: _FutureT[_T1], - __coro_or_future2: _FutureT[_T2], - __coro_or_future3: _FutureT[_T3], - __coro_or_future4: _FutureT[_T4], - __coro_or_future5: _FutureT[_T5], - *, - loop: AbstractEventLoop | None = ..., - return_exceptions: bool = ..., - ) -> Future[ - tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException] - ]: ... - +def gather( + *__coro_or_future: Unpack[_Ts[_FutureT[_T]]], return_exceptions: Literal[False] = ... +) -> Future[tuple[Unpack[_Ts[_T1]]]]: ... def run_coroutine_threadsafe(coro: _FutureT[_T], loop: AbstractEventLoop) -> concurrent.futures.Future[_T]: ... if sys.version_info >= (3, 10):