Skip to content

Design for using async+await with asyncio #1886

Closed
@gvanrossum

Description

@gvanrossum

I'm trying something new here, pouring my thoughts into the issue tracker to get some clarity.

I hope that we'll soon have syntactic support for PEP 492, in particular async def and await (#1808). (Yes, it also supports async for and async with, but these aren't very interesting so I won't mention them.)

I've also made some improvements to the asyncio stubs (python/typeshed#373, merged already) and created a fully annotated example, crawl.py (#1878). But these do not use async def or await; they use generators annotated with @asyncio.coroutine and yield from to wait for coroutines and Futures.

The next step is supporting asyncio code that uses async def and await, and here I am a little stuck. On the one hand, PEP 492 draws a clear distinction between generators and native coroutines (the latter being the ones defined using async def). You can't use a generator with await, and you can't use a native coroutine with yield from. On the other hand, PEP 492 also allows an escape clause: by using the decorator @types.coroutine you can mark a generator as a coroutine, and then await accepts it. The @asyncio.coroutine decorator calls this decorator, in addition to doing other asyncio-specific things (some of which are only apparent in debug mode).

I would like mypy to model all this as well as possible, so that mypy will give a useful error message when you try to use a generator with await or a coroutine with yield from. But it should also understand that a generator decorated with @types.coroutine or @asyncio.coroutine is acceptable for await as well as for yield from (in the latter case it would be even better if it could also keep track of whether the generator containing the yield from is decorated with @asyncio.coroutine).

The final piece of the puzzle (or rather, contribution to the problem) is that it's not easy to specify the type for a decorator that modifies the signature of the function it wraps. What I wish I could do is to declare that the @asyncio.coroutine decorator takes a function with arguments AA and return type Generator[Any, Any, R] and returns a function with arguments AA and return type Awaitable[R] (which is what await requires -- the return value of await is then of type R). And I'd like the decorator to be overloaded so that it also handles a few other cases.

But neither PEP 484 nor mypy supports this "signature algebra", so the best I can think of is to special-case the two decorators (@types.coroutine and @asyncio.coroutine) in mypy, in a similar fashion as how it deals with some other built-in decorators (@property, @classmethod and probably a few more).

[To be continued]

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions