SayPy
SayPy

Reputation: 566

Coroutine was never awaited

I'm using a simple context manager with an asyncio loop inside:

class Runner:
    def __init__(self):
        self.loop = asyncio.get_event_loop()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.loop.close()

    def do_work(self):
        ...
        return self.loop.run_until_complete(asyncio.gather(*futures))

When I use two Runner objects, I get "Coroutine was never awaited" error.

with Runner() as r:
    r.do_work()

with Runner() as r2:
    r2.do_work()

Because a loop was closed in the first Runner(r). Everything works if I don't close a loop in exit, but I don't need to keep it opened. I know that we can have only one loop in a thread, but why it doesn't wait for run_until_complete?

Upvotes: 3

Views: 10755

Answers (1)

Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39516

why it doesn't wait for run_until_complete

Probably something like this happens:

import asyncio


async def test():
    await asyncio.sleep(0.1)


if __name__ ==  '__main__':
    loop = asyncio.get_event_loop()

    loop.run_until_complete(test())
    loop.close()

    loop.run_until_complete(test())

Result:

RuntimeError: Event loop is closed
sys:1: RuntimeWarning: coroutine 'test' was never awaited

How to solve this issue?

Since you're using event loop this way, you can just use new event loop each time:

class Runner:
    def __init__(self):
        self.loop = asyncio.new_event_loop()  # *new*_event_loop


    def do_work(self):
        # Make sure all futures are created 
        # with relevant event loop been set as current
        asyncio.set_event_loop(self.loop)

        # ...
        return self.loop.run_until_complete(asyncio.gather(*futures))

Upvotes: 4

Related Questions