pytest-asyncio: RuntimeError: There is no current event loop in thread 'MainThread'.
My previously passing test is now failing with pytest-asyncio==0.22. I get the error:
self = <Coroutine test_my_test[0]>
    def runtest(self) -> None:
        if self.get_closest_marker("asyncio"):
            self.obj = wrap_in_sync(
                # https://github.com/pytest-dev/pytest-asyncio/issues/596
                self.obj,  # type: ignore[has-type]
            )
>       super().runtest()
../../../miniconda3/envs/py311/lib/python3.11/site-packages/pytest_asyncio/plugin.py:426:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../miniconda3/envs/py311/lib/python3.11/site-packages/pytest_asyncio/plugin.py:804: in inner
    _loop = asyncio.get_event_loop()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <asyncio.unix_events._UnixDefaultEventLoopPolicy object at 0x7f5a92b814d0>
    def get_event_loop(self):
        """Get the event loop for the current context.
        Returns an instance of EventLoop or raises an exception.
        """
        if (self._local._loop is None and
                not self._local._set_called and
                threading.current_thread() is threading.main_thread()):
            self.set_event_loop(self.new_event_loop())
        if self._local._loop is None:
>           raise RuntimeError('There is no current event loop in thread %r.'
                               % threading.current_thread().name)
E           RuntimeError: There is no current event loop in thread 'MainThread'.
../../../miniconda3/envs/py311/lib/python3.11/asyncio/events.py:677: RuntimeError
I assume it’s a coincidence, but just yesterday I switched from
pytestmark = pytest.mark.asyncio
to:
[tool.pytest.ini_options]
asyncio_mode = "auto"
About this issue
- Original URL
 - State: closed
 - Created 8 months ago
 - Comments: 22 (7 by maintainers)
 
@lindycoder I do have some tests which do this with one more level of isolation (where a test calls a sync function, but under the hood that sync function ends up running async code). In my particular case the reason is highly involved and boils down to using an async postgresql context inside alembic, which is sync. (The involved thing is why we decided to this in the first place…). Another example would be testing something like
asyncio.run()(e.g. testing an async repl).Of course if the fixture / test is under one’s control one can simply make it async, but if the sync -> async boundary is under the hood it’s harder.
I don’t know why @qci-amos needs it though, but it’s definitely a valid (if weird) use-case.
We have the same issue as @qci-amos reported (out setup.cfg contains
[tool.pytest.ini_options] asyncio_mode = "auto").pytest assumes that tests are synchronous functions and gives a warning when you try to write
async deftests. pytest-asyncio wraps async tests to in synchronous functions to satisfy pytest. In v.0.21.0, this synchronization wrapper had an explicit reference to the event loop in which the test should run. This reference is no longer present in v0.23.0a1 (see https://github.com/pytest-dev/pytest-asyncio/commit/36b226936e17232535e88ca34f9707cdf211776b) and the synchronization wrappers run in the loop returned byasyncio.get_event_loop().I can see that the order in which fixtures are evaluated has changed from v0.21.0 to v0.23.0a1.
v0.21.0:The logs show that tests fail when the nested_async fixture is setup after event_loop. Note that nested_async calls
asyncio.run(). As 2e0byo already mentioned,asyncio.runsets the current event loop to None when finishing. This causes the synchronization wrappers to fail, because the current event loop is None.I don’t know why the fixtures are evaluated in different order for different parametrizations, but it don’t think it’s relevant for the case.
Although I agree that it’s preferable to use
over
asyncio.run(), the test fails for a non-obvious reason and the error message doesn’t really help.@qci-amos calling
asyncio.runanywhere except the top-level entrypoint is generally frowned upon. The docs sayCalling
runcleans up and stops the executor, which is probably why. Thus it’s not valid to run any async code afterwards (without provisioning a new loop). This is doubtless a surprise topytest-asyncio, since the executor is already stopped when it goes to clean up.FWIW I regard
asyncio.run()as ‘surprising’ code: personally I’d definitely use the async fixture here to avoid the side effect. But there are times when you can’t.(The postgresql case is more fun although I haven’t looked into it:
sync_enginereturns something something greenlets something something.)Ok, here’s a new repro:
Thanks, this version fixed the test I created the repro for, but the other test (which looks the same in this regard to my eye) is still failing. I’ll see if I can make another repro today.
It’s not letting me reopen this @seifertm , but I find my error was indeed separate.
In
conftest.py:In
test_repro.py:gives me:
Thanks @seifertm!
@gabrielmbmb I filed a PR to mark pytest-asyncio v0.22.0 as broken on conda-forge: https://github.com/conda-forge/admin-requests/pull/857
Hey guys, just wanted to mention that
pytest-asyncio==0.22.0hasn’t been yanked in conda-forge https://anaconda.org/conda-forge/pytest-asyncio@lindycoder larger scopes are being discussed over here https://github.com/pytest-dev/pytest-asyncio/issues/657
Thank you for fixing by removing 0.22.0.
I would like to share something regarding this warning:
We have session scoped async fixtures so we have this central fixture
And every single AsyncGenerator fixtures we have actually require event_loop to make sure the teardown is done before the loop is closed.
Sharing this use-case hoping to help further development.