typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

Incorrect return type for asyncio.gather?

Open s-kovacevic opened this issue 5 years ago • 7 comments

asyncio.gather return type from tasks.pyi seem to be different from the actual runtime type.

example.py

import asyncio
from typing import List

async def five() -> int:
    return 5

async def runner() -> List[int]:
    fives = await asyncio.gather(five(), five(), five())
    print(type(fives))  # prints `<class 'list'>`
    print(fives)  # prints `[5, 5, 5]`
    return fives

loop = asyncio.get_event_loop()
result: List[int] = loop.run_until_complete(runner())
$  python3 --version
Python 3.6.6
$  python3 example.py               
<class 'list'>
[5, 5, 5]
$  mypy --version
mypy 0.641
$ mypy example.py                  
example.py:11: error: Incompatible return value type (got "Tuple[int, int, int]", expected "List[int]")

By looking at tasks.pyi I see no overload or any case where gather does not return a Tuple.

s-kovacevic avatar Nov 29 '18 14:11 s-kovacevic

Looking at the implementation of gather() in both Python 3.5 and 3.7, it seems to always return a list future. The problem is that there is no way to annotate it to return a list with different types at each position. Philosophically, gather() should return a tuple.

All fixes I can see have other downsides. -> List[Any] and -> List[Union[_T1, _T2]] etc. lose type and length information. The latter also makes it cumbersome to retrieve values in the general case, where _T1 != _T2.

srittau avatar Nov 29 '18 17:11 srittau

Can't think of any better solution right now. I feel like it is better to lose type information than have it wrong. Were there any similar issues in the past?

s-kovacevic avatar Dec 03 '18 11:12 s-kovacevic

I've just ran into this one, and I agree that List[Any] would be a better solution here. I understand that it loses typing information, but it's better than having an incorrect type altogether. It seems that MyPy agrees to this, as the current return type as reported by reveal_type there is asyncio.Future[builtins.list[Any]].

DevilXD avatar Feb 14 '22 16:02 DevilXD

Is the base issue here that the return type of gather changed after Python 3.7, which means supporting the correct typing would break compatibility with those versions?

aawilson avatar Sep 19 '22 17:09 aawilson

Nevermind, I poked around about in tasks.pyi and I see that the problem I'm getting locally has to do with my interpreter version running LSP not being the version I expect, I see the issue.

aawilson avatar Sep 19 '22 17:09 aawilson

Would TypeVarTuple help with this now? https://peps.python.org/pep-0646/#implications
Once mypy supports it of course https://github.com/python/mypy/issues/12280

Avasam avatar Sep 19 '22 19:09 Avasam

No, because TypeVarTuple can't be used to type a heterogeneous list.

JelleZijlstra avatar Sep 19 '22 19:09 JelleZijlstra