Skip to content

Commit aae1fd7

Browse files
committed
[feat] Raises a MultipleEventLoopsRequested error when a function-scoped loop is pulled in by an async autouse fixture in addition to an event loop with larger scope.
Signed-off-by: Michael Seifert <[email protected]>
1 parent 59afabf commit aae1fd7

File tree

3 files changed

+45
-8
lines changed

3 files changed

+45
-8
lines changed

docs/source/reference/changelog.rst

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Changelog
99
- Deprecates the optional `scope` keyword argument to `pytest.mark.asyncio` for API consistency with ``pytest_asyncio.fixture``. Users are encouraged to use the `loop_scope` keyword argument, which does exactly the same.
1010
- Raises an error when passing `scope` or `loop_scope` as a positional argument to ``@pytest.mark.asyncio``. `#812 <https://github.com/pytest-dev/pytest-asyncio/issues/812>`_
1111
- Fixes a bug that caused module-scoped async fixtures to fail when reused in other modules `#862 <https://github.com/pytest-dev/pytest-asyncio/issues/862>`_ `#668 <https://github.com/pytest-dev/pytest-asyncio/issues/668>`_
12+
- Improves detection of multiple event loops being requested by the same test in strict mode `#868 <https://github.com/pytest-dev/pytest-asyncio/issues/868>`_
1213

1314

1415
0.23.8 (2024-07-17)

pytest_asyncio/plugin.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -730,14 +730,6 @@ def pytest_generate_tests(metafunc: Metafunc) -> None:
730730
event_loop_fixture_id = event_loop_node.stash.get(_event_loop_fixture_id, None)
731731

732732
if event_loop_fixture_id:
733-
# This specific fixture name may already be in metafunc.argnames, if this
734-
# test indirectly depends on the fixture. For example, this is the case
735-
# when the test depends on an async fixture, both of which share the same
736-
# event loop fixture mark.
737-
if event_loop_fixture_id in metafunc.fixturenames:
738-
return
739-
fixturemanager = metafunc.config.pluginmanager.get_plugin("funcmanage")
740-
assert fixturemanager is not None
741733
if "event_loop" in metafunc.fixturenames:
742734
raise MultipleEventLoopsRequestedError(
743735
_MULTIPLE_LOOPS_REQUESTED_ERROR.format(
@@ -746,6 +738,14 @@ def pytest_generate_tests(metafunc: Metafunc) -> None:
746738
scoped_loop_node=event_loop_node.nodeid,
747739
),
748740
)
741+
# This specific fixture name may already be in metafunc.argnames, if this
742+
# test indirectly depends on the fixture. For example, this is the case
743+
# when the test depends on an async fixture, both of which share the same
744+
# event loop fixture mark.
745+
if event_loop_fixture_id in metafunc.fixturenames:
746+
return
747+
fixturemanager = metafunc.config.pluginmanager.get_plugin("funcmanage")
748+
assert fixturemanager is not None
749749
# Add the scoped event loop fixture to Metafunc's list of fixture names and
750750
# fixturedefs and leave the actual parametrization to pytest
751751
# The fixture needs to be appended to avoid messing up the fixture evaluation
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from textwrap import dedent
2+
3+
from pytest import Pytester
4+
5+
6+
def test_autouse_fixture_in_different_scope_triggers_multiple_event_loop_error(
7+
pytester: Pytester,
8+
):
9+
pytester.makepyfile(
10+
dedent(
11+
"""\
12+
import asyncio
13+
import pytest
14+
import pytest_asyncio
15+
16+
loop: asyncio.AbstractEventLoop
17+
18+
@pytest_asyncio.fixture(autouse=True)
19+
async def autouse_fixture():
20+
pass
21+
22+
@pytest_asyncio.fixture(scope="session")
23+
async def any_fixture():
24+
global loop
25+
loop = asyncio.get_running_loop()
26+
27+
@pytest.mark.asyncio(scope="session")
28+
async def test_runs_in_session_scoped_loop(any_fixture):
29+
global loop
30+
assert asyncio.get_running_loop() is loop
31+
"""
32+
)
33+
)
34+
result = pytester.runpytest("--asyncio-mode=strict")
35+
result.assert_outcomes(errors=1)
36+
result.stdout.fnmatch_lines("*MultipleEventLoopsRequestedError: *")

0 commit comments

Comments
 (0)