-
Notifications
You must be signed in to change notification settings - Fork 285
Description
In the wild, today, if you await something, there are several potentially valid things to bubble back out from the innermost await
- an
asyncio.Future - a curio "trap" (which I gather is defined as something like
Tuple[curio.traps.Traps, Any, ...]) - a Trio trap, (which I gather is defined as something like
Iterable[WaitTaskRescheduled]although I haven't quite found the bottom of that stack) - a
Deferred
Not all of these are mutually compatible. However, Awaitable is parameterized only on one type - the type of its result. This results in code like this:
def some_deferred() -> Awaitable[int]: ...
def some_future() -> Awaitable[int]: ...
async def x() -> Awaitable[List[int]]:
y = []
y.append(await some_deferred())
y.append(await some_future())
return y
type-checking even though it should fail.
I'd like to be able to express this as
def some_deferred() -> Awaitable[int, Deferred]: ...
def some_future() -> Awaitable[int]: ... # presumably Future is the default
async def x() -> Awaitable[List[int]]:
y = []
y.append(await some_deferred()) # <-- automatically specialize to `Awaitable[List[int], Deferred]` here, if possible?
y.append(await some_future()) # <-- type error!
return y
This is made slightly more complex by the fact that some awaitables are mutually intelligible - for example, anything that awaits a Deferred should eventually be able to await a Future directly, once we've made a few more changes to Twisted. We could also do this in the other direction if __await__ were changed to pass the loop along. Whereas, some of these types are incompatible by design; my understanding is that await implies a completely different, and somewhat higher-level, scheduling protocol in Trio, for example.