Skip to content
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

Clarification: return type for asyncio.gather()? #3243

Closed
bsolomon1124 opened this issue Sep 18, 2019 · 3 comments
Closed

Clarification: return type for asyncio.gather()? #3243

bsolomon1124 opened this issue Sep 18, 2019 · 3 comments

Comments

@bsolomon1124
Copy link
Contributor

bsolomon1124 commented Sep 18, 2019

I've come across a source of confusion for asyncio.gather(). It may very well be user error rather than an incorrect annotation. (Motivated by this Stack Overflow post.)

The annotation return types for gather() are Future[Tuple[_T1]], Future[Tuple[_T1, _T2]], and so on.

However, the result of return await asyncio.gather(*tasks) is List. I.e.:

import asyncio
from typing import List

async def foo(x) -> int:
    await asyncio.sleep(x / 2)
    return x

async def main() -> List[int]:
    return await asyncio.gather(*(foo(i) for i in (1, 2, 3)))

if __name__ == "__main__":
    print(asyncio.run(main()))

This runs find, printing [1, 2, 3]; await asyncio.gather() produces a List[int].

However, mypy complains that:

mypytest.py:9: error: Incompatible types in assignment (expression has type "Tuple[Any, ...]", variable has type "List[int]")

Why does this ambiguity exist? How can I provide a correct type hint for async def main()?


I'm looking at typeshed master branch as of 0602840 fyi + mypy 0.720.

@srittau
Copy link
Collaborator

srittau commented Sep 18, 2019

I assume it's done like this in the stubs, because typing's type system only allows Lists with consistent types, as opposed to Tuples. This allows you to write code like this and have it correctly type-checked:

x, y, z = await gather(foo(), bar(), baz())

Where foo, bar, and baz each return a different type.

But this should at least be documented in the stubs.

@bsolomon1124
Copy link
Contributor Author

bsolomon1124 commented Sep 18, 2019

@srittau Yes, the iterable unpacking portion of that code makes sense but, in my own view, this is a bit like calling the sky orange 😉 gather() does return a list (of potentially heterogeneous items).

Looking back though, PR #1550 discussed this specifically, followed by c5f1e90. So if we agree in something, it's that it could be documented a bit more clearly in case, for instance, someone tries to call .append() on the result of gather().

@tsafs
Copy link

tsafs commented Jul 5, 2022

I assume it's done like this in the stubs, because typing's type system only allows Lists with consistent types, as opposed to Tuples. This allows you to write code like this and have it correctly type-checked:

x, y, z = await gather(foo(), bar(), baz())

Where foo, bar, and baz each return a different type.

But this should at least be documented in the stubs.

That solved this error for me

Cannot unpack 1 value into 2 variables [bad-unpacking]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants