How can I await inside future-like object's __await__?

asyncio gather
coroutine was never awaited
object dict can 't be used in 'await' expression
asyncio wait_for timeout
asyncio timeout error
asyncio task vs future
asyncio gather example
python async parallel

PEP 0492 adds new __await__ magic method. Object that implements this method becomes future-like object and can be awaited using await. It's clear:

import asyncio


class Waiting:
    def __await__(self):
        yield from asyncio.sleep(2)
        print('ok')

async def main():
    await Waiting()

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Ok, but what if I want to call some async def defined function instead of asyncio.sleep? I can't use await because __await__ is not async function, I can't use yield from because native coroutines requires await expression:

async def new_sleep():
    await asyncio.sleep(2)

class Waiting:
    def __await__(self):
        yield from new_sleep()  # this is TypeError
        await new_sleep()  # this is SyntaxError
        print('ok')

How can I solve it?

Use direct __await__() call:

async def new_sleep():
    await asyncio.sleep(2)

class Waiting:
    def __await__(self):
        return new_sleep().__await__()

The solution was recommended by Yury Selivanov (the author of PEP 492) for aioodbc library

Futures, Coroutines can await on Future objects until they either have a result or an exception set, or until they are cancelled. Typically Futures are used to enable low-level callback-based code (e.g. in protocols implemented using asyncio transports) to interoperate with high-level async/await code. Future Object¶ class asyncio.Future (*, loop=None) ¶ A Future represents an eventual result of an asynchronous operation. Not thread-safe. Future is an awaitable object. Coroutines can await on Future objects until they either have a result or an exception set, or until they are cancelled.

Short version: await foo can be replaced by yield from foo.__await__()


Combining all the ideas from the other answers -

in the simplest case, just delegating to another awaitable works:

def __await__(self):
    return new_sleep().__await__()

This works because the __await__ method returns an iterator (see PEP 492), so returning another __await__'s iterator is fine.

This means, of course, that we can't change the suspension behavior of the original awaitable at all. The more general approach is to mirror the await keyword and use yield from - this lets us combine multiple awaitables' iterators into one:

def __await__(self):
    # theoretically possible, but not useful for my example:
    #yield from something_else_first().__await__()
    yield from new_sleep().__await__()

Here's the catch: this is not doing exactly the same thing as the first variant! yield from is an expression, so to do exactly the same as before, we need to also return that value:

def __await__(self):
    return (yield from new_sleep().__await__())

This directly mirrors how we would write proper delegation using the await syntax:

    return await new_sleep()

extra bit - what's the difference between these two?

def __await__(self):
    do_something_synchronously()
    return new_sleep().__await__()

def __await__(self):
    do_something_synchronously()
    return (yield from new_sleep().__await__())

The first variant is a plain function: when you call it, do_... is executed and an iterator returned. The second is a generator function; calling it doesn't execute any of our code at all! Only when the returned iterator is yielded for the first time will do_... be executed. This makes a difference in the following, a little contrived situation:

def foo():
    tmp = Waiting.__await__()
    do_something()
    yield from tmp

How can I await inside future-like object's __await__?, Futures, Coroutines can await on Future objects until they either have a result or an exception set, or until they are cancelled. Coroutines and Tasks, Coroutines declared with the async/await syntax is the preferred way of writing The asyncio.create_task() function to run coroutines concurrently as asyncio Tasks . python - How can I await inside future-like object's__await__? PEP 0492 adds new__await__ magic method. Object that implements this method becomes future-like object and can be awaited using await. It's clear: import asyncio class Waiting: def__await__(se…

To await inside a __await__ function, use the following code:

async def new_sleep():
    await asyncio.sleep(1)


class Waiting:
    def __await__(self):
        yield from new_sleep().__await__()
        print('first sleep')
        yield from new_sleep().__await__()
        print('second sleep')
        return 'done'

Asynchronous programming: futures, async, await, As the following two examples show, the async and await keywords result in asynchronous code that looks a lot like synchronous code. The only differences are  As soon as you actually use an await, as for example await Future.delayed(new Duration(seconds: 2)); the event loop will now become active again. Because an await allows concurrency in the same thread, it must allow the event loop to continue, hence the result of using an await instead of sleep will look more like this.

I didn't understand why I can't yield from native coroutine inside __await__, but looks like it's possible to yield from generator coroutine inside __await__ and yield from native coroutine inside that generator coroutine. It works:

async def new_sleep():
    await asyncio.sleep(2)

class Waiting:
    def __await__(self):
        @asyncio.coroutine
        def wrapper(coro):
            return (yield from coro)
        return (yield from wrapper(new_sleep()))

Futures, async, await: Threading in Flutter, This reference object is known as a Future. The main thread continues chugging along its merry way. When the waiting activity is finally resolved,  const forEachLoop = _ => { console.log('Start') fruitsToGet.forEach(fruit => { // Send a promise for each fruit }) console.log('End') } Next, we’ll try to get the number of fruits with getNumFruit. (Notice the async keyword in the callback function. We need this async keyword because await is in the callback function).

Use a decorator.

def chain__await__(f):
    return lambda *args, **kwargs: f(*args, **kwargs).__await__()

Then write __await__ as a native coroutine.

async def new_sleep():
    await asyncio.sleep(2)

class Waiting:
    @chain__await__
    async def __await__(self):
        return await new_sleep()

Dart asynchronous programming: Futures - Dart, Thanks to Dart language features like async-await, you might never need to use But you're almost certain to encounter futures in your Dart code. A good thing to know about futures is that they're really just an API built to  You can use the await operator only in a method, lambda expression, or anonymous method that is modified by the async keyword. Within an async method, you can't use the await operator in the body of a synchronous function, inside the block of a lock statement, and in an unsafe context.

18.5.3. Tasks and coroutines, If disambiguation is needed we will call it a coroutine object ( iscoroutine() result = await future or result = yield from future – suspends the coroutine until the In this documentation, some methods are documented as coroutines, even if they  The await operator is used to wait for a Promise. It can only be used inside an async function. Syntax [rv] = await expression; expression A Promise or any value to wait for. rv. Returns the fulfilled value of the promise, or the value itself if it's not a Promise. Description

Guide to Concurrency in Python with Asyncio ⋆ Mark McDonnell, There are a few different types of objects in Python that help support Ultimately, something is awaitable if it can be used in an await expression. Note: Futures is a low-level type and so you shouldn't need to worry about it too much if you're not a library/framework developer (as you should be  But it’s another demonstration of how promises can still come into play in async/await land. Pitfall 3: your whole stack needs to be async If I start using await somewhere, I now have the

Async IO in Python: A Complete Walkthrough – Real Python, As you'll see in the next section, the benefit of awaiting something, including As a result, it returns a single future object, and, if you await asyncio.gather() and  Every time you create an async method, the compiler generates a state machine for it. Then for each await inside of that method, it does the following: Executes the method to the await expression Checks if the method being awaited has already completed

Comments
  • Is there any reason you can't just implement it as a separate async function inside of the Waiting class? Thus, await Waiting.new_sleep() ?
  • @songololo - yes, if you wan't to have your own class of awaitables, that's why they provide the __await__ method. Something will call await or e.g. asyncio.wait_for on it - and it won't be called from your code.
  • this answer: stackoverflow.com/a/46722215/371191 is a little more general, as it allows awaiting multiple awaitables
  • Ideally should have a functools.wraps here
  • One footnote to this answer - the sync_await function is a "generator based coroutine", which Python 3.7 distignuishes from async def, the "real" coroutines. The former will be removed in Python 3.10 - so my answer will stop working then; however we'll all have forgotten 3.6 till then (instead of having it almost everywhere).