Although the following program successfully runs (and prints 42), neither pyright nor mypy accept it:
import asyncio
from collections.abc import AsyncGenerator
async def gen() -> AsyncGenerator[int, None]:
yield 42
async def main() -> None:
print(await asyncio.create_task(anext(gen())))
asyncio.run(main())
Pyright produces the following type error (mypy’s error is similar):
Argument of type "Awaitable[int]" cannot be assigned to parameter "coro" of type "_CoroutineLike[_T@create_task]" in function "create_task"
"Awaitable[int]" is not assignable to "Coroutine[Any, Any, _T@create_task]"
The reason for this type error is that the definition of the collections.abc.AsyncGenerator protocol on typeshed says that __anext__ returns an awaitable whereas asyncio.create_task expects an actual coroutine, both in its type and at runtime. The program above runs successfully nevertheless because the __anext__ method of an asynchronous generator defined using the async def/yield syntax does indeed return a coroutine. Thus, both pyright and mypy reject a very legitimate program.
There’s a second protocol for asynchronous generators, namely types.AcyncGeneratorType. Its docs say
types.AsyncGeneratorType
The type of asynchronous generator-iterator objects, created by asynchronous generator functions.
and its definition on typeshed says that __anext__ returns a coroutine. Thus, the program above would type check if the return type of gen was changed to types.AsyncGeneratorType[int, None]. However, pyright and mypy insist that the return type of gen must be collections.abc.AsyncGenerator (or one of its super types).
I would like to solve this problem and arrive at a situation where the program above can be typed in a way that is accepted by the common type checkers for Python. I can think of two approaches:
- Change the definition of
collections.abc.AsyncGeneratorsuch that__anext__returns a coroutine rather than just any awaitable. - Change the type checkers to allow for annotating
gen’s return type astypes.AsyncGeneratorTypeand adjust their type inference accordingly.
Which of these two approaches is the right one to pursue? Is there even a clear cut winner or is this something that needs detailed discussion?