Python 3.10 asyncio.gather() shows DeprecationWarning: There is no current event loop

Viewed 11818

I have a Django app and in one of its views I use asyncio in order to make some concurent requests to an external component.

Here is the idea:

import asyncio


async def do_request(project):
    result = ...

    return result

def aggregate_results(projects: list):
    loop = asyncio.new_event_loop()

    asyncio.set_event_loop(loop)

    results = loop.run_until_complete(
        asyncio.gather(*(do_request(project) for project in projects))
    )

    loop.close()

    return zip(projects, results)

Well, when I run the tests I get DeprecationWarning: There is no current event loop at this line:

        asyncio.gather(*(do_request(project) for project in projects))

How should I interpret this warning and what do I need to change to get rid of it? Thanks!

1 Answers

According to the documentation, this happens because there is no event loop running at the time when you call gather.

Deprecated since version 3.10: Deprecation warning is emitted if no positional arguments are provided or not all positional arguments are Future-like objects and there is no running event loop.

As you've probably noticed, your code works. It will continue to work and you can ignore the deprecation warning as long as you use 3.10. At some point in the future, though, this may change to a runtime error.

If you'll bear with me a moment, the recommended way to run an event loop is with run, not loop.run_until_complete.

def aggregate_results(projects: list):
    results = asyncio.run(asyncio.gather(*(do_request(project) for project in projects)))
    return zip(projects, results)

This, however, won't actually work. You'll instead get an exception

ValueError: a coroutine was expected, got <_GatheringFuture pending>

The fix is to instead await gather from another coroutine.

async def get_project_results(projects: list):
    results = await asyncio.gather(*(do_request(project) for project in projects))
    return results

def aggregate_results(projects: list):
    results = asyncio.run(get_project_results(projects))
    return zip(projects, results)

(You could also use get_project_results with your version of aggregate_results.)

Related