This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ValueError: a coroutine was expected with asyncio.run
Type: Stage: resolved
Components: asyncio Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: asvetlov, natim, vstinner, yselivanov
Priority: normal Keywords:

Created on 2019-03-07 09:08 by natim, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (3)
msg337374 - (view) Author: Rémy Hubscher [:natim] (natim) * Date: 2019-03-07 09:08
Refs: https://github.com/Martiusweb/asynctest/issues/114

I was trying to mock a `asyncio.run(asyncio.gather())` call and I discovered that while it was working with `loop.run_until_complete` it wasn't with `asyncio.run`

Is there a reason for this difference of behaviour?

```
import asyncio
from unittest.mock import Mock


class AsyncMock(Mock):

    def __call__(self, *args, **kwargs):
        sup = super(AsyncMock, self)
        async def coro():
            return sup.__call__(*args, **kwargs)
        return coro()

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

mocked_function = AsyncMock()

asyncio.run(asyncio.gather(mocked_function()))
```

```
import asyncio
from unittest.mock import Mock


class AsyncMock(Mock):

    def __call__(self, *args, **kwargs):
        sup = super(AsyncMock, self)
        async def coro():
            return sup.__call__(*args, **kwargs)
        return coro()

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

mocked_function = AsyncMock()

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(mocked_function()))
```
msg337376 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-03-07 09:30
asyncio.run() requires a coroutine, whereas gather() returns a subclass of asyncio.Future.
https://docs.python.org/dev/library/asyncio-task.html#asyncio.run

You can wrap gather() into a coroutine like that:
---
async def main():
    await asyncio.gather(mocked_function())

asyncio.run(main())
---

loop.run_until_complete() is different. It requires a "future", not a coroutine.
https://docs.python.org/dev/library/asyncio-eventloop.html#asyncio.loop.run_until_complete

gather() creates a future which is linked to the current event loop, whereas asyncio.run() creates a new event loop for the lifetime of run(). You should not pass a Future from an event loop to another event loop.

It's not a bug ;-)
msg337377 - (view) Author: Rémy Hubscher [:natim] (natim) * Date: 2019-03-07 09:31
Thank you for the clarification :)
History
Date User Action Args
2022-04-11 14:59:12adminsetgithub: 80403
2019-03-07 09:31:24natimsetmessages: + msg337377
2019-03-07 09:30:53vstinnersetstatus: open -> closed

nosy: + vstinner
messages: + msg337376

resolution: not a bug
stage: resolved
2019-03-07 09:08:41natimcreate