- Notifications
You must be signed in to change notification settings - Fork 167
Description
First of all, thanks for the great pytest plugin!
Also, I like the idea of being able to specify event_loop scopes explicitly and separately to the fixture scopes.
While playing with this, I kept running into issues that my "session" scoped event_loop seemed to change between tests that were running in different files, but only if certain other tests were run...
I think this example reproduces the issues in a single file. I recognize that the docs explicitly advise against doing this, but I hope it makes the problem easier to reason about.
Here's the example.
import pytest_asyncio import asyncio import pytest class FakeAsyncConnection: def __init__(self, loop): self.loop = loop async def do_something(self): # Check if the current loop is the same as the one with which the # connection was created if asyncio.get_event_loop() is not self.loop: raise RuntimeError( "This connection is being used with a different event loop!") return "Success" @pytest_asyncio.fixture(scope="module", loop_scope="module") async def async_connection(): """Set up a async connection object with module scope.""" event_loop = asyncio.get_event_loop() print(f"Setting up fixture: event_loop_id {id(event_loop)}") connection = FakeAsyncConnection(event_loop) yield connection @pytest.mark.asyncio(loop_scope="module") async def test_use_module_scope_loop_1(async_connection): """Use module loop""" print(f"Test using loop with id: {id(asyncio.get_event_loop())}") result = await async_connection.do_something() assert result == "Success" @pytest.mark.asyncio(loop_scope="module") async def test_use_module_scope_loop_2(async_connection): """Use module loop again""" print(f"Test using loop with id: {id(asyncio.get_event_loop())}") result = await async_connection.do_something() assert result == "Success" @pytest.mark.asyncio(loop_scope="function") async def test_use_function_scope_loop_1(async_connection): """Use function loop""" print(f"Test using loop with id: {id(asyncio.get_event_loop())}") with pytest.raises(RuntimeError, match="This connection is being used with a different event loop!"): # This should raise an error because the connection is being used with a different loop await async_connection.do_something() @pytest.mark.asyncio(loop_scope="module") async def test_use_module_scope_loop_3(async_connection): """Unexpectedly fail to use module scope again""" print(f"Test using loop with id: {id(asyncio.get_event_loop())}") result = await async_connection.do_something() assert result == "Success"I would expect all tests to pass, however, the final test test_use_module_scope_loop_3 fails only if the test_use_function_scope_loop_1 is present. If the function scope one is commented out, the final test does pass (as expected).
The fixtures aren't obviously set up incorrectly (running with --setup-show):
SETUP S event_loop_policy SETUP M tests/test_a.py::<event_loop> (fixtures used: event_loop_policy) SETUP M async_connection tests/test_a.py::test_use_module_scope_loop_1 (fixtures used: async_connection, event_loop_policy, request, tests/test_a.py::<event_loop>). tests/test_a.py::test_use_module_scope_loop_2 (fixtures used: async_connection, event_loop_policy, request, tests/test_a.py::<event_loop>). SETUP F event_loop tests/test_a.py::test_use_function_scope_loop_1 (fixtures used: async_connection, event_loop, event_loop_policy, request). TEARDOWN F event_loop tests/test_a.py::test_use_module_scope_loop_3 (fixtures used: async_connection, event_loop_policy, request, tests/test_a.py::<event_loop>)F TEARDOWN M async_connection TEARDOWN M tests/test_a.py::<event_loop> TEARDOWN S event_loop_policy But for some reason I don't understand, the module scoped event loop changes for the last test.
The printed loop ids tell the same story... The fixture and first two tests all get the the same loop_id as expected. The function scope test gets a new one as expected. Then the final module scope test also gets a new loop_id (different from both previous loop_ids) unexpectedly.
Versions:
python: 3.12.7
pytest: 8.3.3
pytest-asyncio: 0.24.0
Also, my pytest settings are:
[tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope="function"