-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More precisely typehint asyncio.gather up to 5 params #1550
More precisely typehint asyncio.gather up to 5 params #1550
Conversation
stdlib/3.4/asyncio/tasks.pyi
Outdated
@@ -8,6 +8,11 @@ from .futures import Future | |||
__all__: List[str] | |||
|
|||
_T = TypeVar('_T') | |||
_T1 = TypeVar('_T') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to be named _T1
def gather(*coros_or_futures: _FutureT[_TAny], | ||
loop: AbstractEventLoop = ..., return_exceptions: bool = False) -> Future[List[_TAny]]: ... | ||
@overload | ||
def gather(coro_or_future1: _FutureT[_T1], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add *,
after the last coro_or_future to indicate that the remaining arguments are keyword-only.
stdlib/3.4/asyncio/tasks.pyi
Outdated
loop: AbstractEventLoop = ..., return_exceptions: bool = False) -> Future[List[_TAny]]: ... | ||
@overload | ||
def gather(coro_or_future1: _FutureT[_T1], | ||
loop: AbstractEventLoop = ..., return_exceptions: bool = False) -> Future[Tuple[_T1]]: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like it actually always returns a List
. Unfortunately, we can't specify how many elements a List
contains in the type system.
Maybe it's acceptable to lie here and pretend that it returns a tuple, but https://docs.python.org/3/library/asyncio-task.html#asyncio.gather does explicitly say that it returns "a list".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last overload could use -> List[Any]
instead. I'm not sure what issues specifying the incorrect type hint here would imply for code that explicitly relies on that.
I'm opened to thoughts about how to better approach this or completely abandon this and just accept life with cast
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somebody could be doing
lst = await asyncio.gather(some_coro(), some_other_coro())
lst.append(some_value)
I don't think I would write code like that, but somebody might. We have to decide whether the advantage of getting more precise types in the common case outweighs the risk of false positive type errors on code like this.
Tests are failing with |
You need to add a |
This PR is oddly missing the 3-argument case... |
An astute observation! |
@carljm Thank you for identifying and taking care of my mistake with the followup PR! |
And luckily this fix made it into 0.530!
|
Hi all, one question a few years later about this discussion. @LiraNuna had mentioned:
Is there a reason this was decided against as a final overload? @overload
def gather(
coro_or_future1: _FutureT[Any],
*,
loop: AbstractEventLoop = ...,
return_exceptions: bool = False
) -> Future[List[Any]]: ... Related: issue #3243 |
It does make sense to use |
@JelleZijlstra I can submit a PR, but I'm unclear on something. The return would be @overload
def gather(
*aws: _FutureT[Any],
*,
loop: AbstractEventLoop = ...,
return_exceptions: bool = False
) -> Future[List[Any]]: ... Or would this call for a handful more overloads with different counts of |
I think you can just change the last current overload, which was as follows as of this PR:
And change the return type to use a List instead of a Tuple. The coro_or_future 1 through 6 are needed to distinguish this overload from the ones before it. We could of course add more overloads with a fixed number of arguments if we feel a need. |
Stems from PR python#1550/ Issue python#3243.
Since mypy/typing lacks a mechanism to describe variadic templates (See python/typing#193), a temporary solution was proposed to at least support some common cases of 1-5 arguments.
This PR mimics the current hack implemented for
zip
:typeshed/stdlib/3/builtins.pyi
Lines 868 to 886 in 4491e41