Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

event_loop not found for multiple test modules #862

Closed
TE-YongweiSun opened this issue Jun 21, 2024 · 7 comments · Fixed by #906
Closed

event_loop not found for multiple test modules #862

TE-YongweiSun opened this issue Jun 21, 2024 · 7 comments · Fixed by #906
Labels
Milestone

Comments

@TE-YongweiSun
Copy link

I just want to use module scope fixture but I get an error:

[environment]
python==3.10.14
pytest==8.2.2
pytest-asyncio==0.23.7

[Directory]

tests/conftest.py:

import pytest_asyncio
@pytest_asyncio.fixture(scope="module")
async def foo():
    yield "a value"

tests/test_1.py:

import pytest
@pytest.mark.asyncio
async def test_func(foo):
        print("test_1 test_func", foo)

tests/test_2.py:

import pytest
@pytest.mark.asyncio
async def test_func(foo):
    print("test_2 test_func", foo)

[error]

# pytest -s tests/
============================= test session starts ==============================
platform linux -- Python 3.10.14, pytest-8.2.2, pluggy-1.5.0
rootdir: /home/sunyw
plugins: asyncio-0.23.7
asyncio: mode=strict
collected 2 items                                                              

tests/test_1.py .                                                        [ 50%]
tests/test_2.py E                                                        [100%]

==================================== ERRORS ====================================
_________________________ ERROR at setup of test_func __________________________
file /home/xxx/tests/test_2.py, line 3
  @pytest.mark.asyncio
  async def test_func(foo):
      print("test_2 test_func", foo)
file /home/xxx/tests/conftest.py, line 13
  @pytest_asyncio.fixture(scope="module")
  async def foo():
      yield "a value"
E       fixture 'tests/test_1.py::<event_loop>' not found
>       available fixtures: _session_event_loop, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, event_loop, event_loop_policy, foo, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tests/test_2.py::<event_loop>, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
>       use 'pytest --fixtures [testpath]' for help on them.

/home/xxx/tests/conftest.py:13
=========================== short test summary info ============================
ERROR tests/test_2.py::test_func
========================== 1 passed, 1 error in 0.01s ==========================

according to the document Decorators:

All scopes are supported, but if you use a non-function scope you will need to redefine the event_loop fixture to have the same or broader scope. Async fixtures need the event loop, and so must have the same or narrower scope than the event_loop fixture.

I add event_loop fixture in conftest.py:

import pytest_asyncio
import asyncio
import pytest

@pytest.fixture(scope="module")
def event_loop(request):
    loop = asyncio.get_event_loop_policy().get_event_loop()
    yield loop
    loop.close()

@pytest_asyncio.fixture(scope="module")
async def foo():
    yield "a value"

But this error is still there.

@erwanlfrt
Copy link

Same issue for me, I have the same event_loop as @TE-YongweiSun in conftest.py and with pytest-asyncio v.0.21.1 no problem but with the latest version v0.23.6 I have the notorious attached to a different loop issue.

Logs:

E   RuntimeError: Task <Task pending name='Task-6' coro=<_wrap_asyncgen_fixture.<locals>._asyncgen_fixture_wrapper.<locals>.setup() running at /opt/acc-py/venvs/acc-py-venv/lib/python3.11/site-packages/pytest_asyncio/plugin.py:326> cb=[_run_until_complete_cb() at /opt/acc-py/base/2023.06/lib/python3.11/asyncio/base_events.py:180]> got Future <Future pending cb=[Protocol._on_waiter_completed()]> attached to a different loop

For somehow the fixture event_loop is not used anymore.

@seifertm
Copy link
Contributor

seifertm commented Jul 15, 2024

Starting from pytest-asyncio v0.23, every level of the pytest test collection hierarchy has its own asyncio event loop. By default, tests marked with @pytest.mark.asyncio are run in a function-scope event loop, i.e. the event loop is refreshed before every test and closed afterwards. A test marked with @pytest.mark.asyncio(scope="module") is run in an asyncio event loop that is valid for the scope of an entire module, for example.

Unfortunately, pytest-asyncio v0.23 falsely assumes that the caching scope and event loop scope for async fixtures are the same. In your example, this means that foo is run in a module-scoped loop, whereas tests/test_1.py::test_func and tests/test_2.py::test_func are each run in a different, function-scope event loop.

You'll want to adjust your tests to use

@pytest.mark.asyncio(scope="module")
async def test_func(foo):
    ...

for everything to run in the same event loop.

Is this something that you can do in your codebase (not the example)?

@seifertm seifertm added the needsinfo Requires additional information from the issue author label Jul 15, 2024
@seifertm
Copy link
Contributor

Closing this issue, because I don't have enough information to take any action.

Feel free to continue adding comments, though.

@seifertm seifertm closed this as not planned Won't fix, can't repro, duplicate, stale Jul 31, 2024
@cstruct
Copy link
Contributor

cstruct commented Aug 1, 2024

I have the same issue and would like the issue re-opened. Adding scope to my marks does no difference.

conftest.py

import pytest_asyncio
@pytest_asyncio.fixture(scope="module")
async def foo():
    yield "a value"

tests/test_1.py

import pytest
@pytest.mark.asyncio(scope="module")
async def test_func(foo):
    print("test_1 test_func", foo)

tests/test_2.py

import pytest
@pytest.mark.asyncio(scope="module")
async def test_func(foo):
    print("test_2 test_func", foo)

Test run output:

================================================================================================ test session starts =================================================================================================
platform darwin -- Python 3.12.0, pytest-8.3.2, pluggy-1.5.0
rootdir: /private/var/folders/cq/77qr3h853b72gvhxlj7vzv7h0000gn/T/tmp.sso6hseXlG/foo
configfile: pyproject.toml
plugins: asyncio-0.23.8
asyncio: mode=Mode.STRICT
collected 2 items

tests/test_1.py .                                                                                                                                                                                              [ 50%]
tests/test_2.py E                                                                                                                                                                                              [100%]

======================================================================================================= ERRORS =======================================================================================================
____________________________________________________________________________________________ ERROR at setup of test_func _____________________________________________________________________________________________
file /private/var/folders/cq/77qr3h853b72gvhxlj7vzv7h0000gn/T/tmp.sso6hseXlG/foo/tests/test_2.py, line 4
  @pytest.mark.asyncio(scope="module")
  async def test_func(foo):
      print("test_2 test_func", foo)
file /private/var/folders/cq/77qr3h853b72gvhxlj7vzv7h0000gn/T/tmp.sso6hseXlG/foo/conftest.py, line 4
  @pytest_asyncio.fixture(scope="module")
  async def foo():
      yield "a value"
E       fixture 'tests/test_1.py::<event_loop>' not found
>       available fixtures: _session_event_loop, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, event_loop, event_loop_policy, foo, foo::<event_loop>, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tests/test_2.py::<event_loop>, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
>       use 'pytest --fixtures [testpath]' for help on them.

/private/var/folders/cq/77qr3h853b72gvhxlj7vzv7h0000gn/T/tmp.sso6hseXlG/foo/conftest.py:4
============================================================================================== short test summary info ===============================================================================================
ERROR tests/test_2.py::test_func
============================================================================================= 1 passed, 1 error in 0.01s =============================================================================================

@seifertm seifertm reopened this Aug 1, 2024
@seifertm seifertm added bug and removed needsinfo Requires additional information from the issue author labels Aug 1, 2024
@seifertm seifertm added this to the v1.0 milestone Aug 1, 2024
@seifertm
Copy link
Contributor

seifertm commented Aug 1, 2024

Thanks for the reproducer @cstruct !

This seems to be related to the fixture processing code in pytest-asyncio. Async fixtures are processed at collection time. It looks like foo references the event loop of test_1.py, even though it's being re-evaluated in test_2.py. At that point, the event loop of test_1.py is no longer available.

See also #668

@cstruct
Copy link
Contributor

cstruct commented Aug 1, 2024

Thank you for the quick response! 🤗
I'll spend some time this weekend and see if I can help with a fix. ☺️

cstruct added a commit to cstruct/pytest-asyncio that referenced this issue Aug 5, 2024
Caching of fixture preprocessing is now also keyed by event loop id,
sync fixtures can be processed if they are wrapping a async fixture,
each async fixture has a mapping from root scope names to fixture id
that is now used to dynamically get the event loop fixture.

This fixes pytest-dev#862.
github-merge-queue bot pushed a commit that referenced this issue Aug 9, 2024
Caching of fixture preprocessing is now also keyed by event loop id,
sync fixtures can be processed if they are wrapping a async fixture,
each async fixture has a mapping from root scope names to fixture id
that is now used to dynamically get the event loop fixture.

This fixes #862.
seifertm pushed a commit to cstruct/pytest-asyncio that referenced this issue Aug 9, 2024
…n reused in other modules.

Async fixture synchronizers now choose the event loop for the async fixutre at runtime rather than relying on collection-time information.

This fixes pytest-dev#862.
github-merge-queue bot pushed a commit that referenced this issue Aug 9, 2024
…n reused in other modules.

Async fixture synchronizers now choose the event loop for the async fixutre at runtime rather than relying on collection-time information.

This fixes #862.
@seifertm
Copy link
Contributor

seifertm commented Aug 9, 2024

The fix is available in the pytest-async v0.24.0a1 pre-release.

UpstreamData added a commit to UpstreamDataInc/goosebit that referenced this issue Aug 27, 2024
Update pytest-asyncio because it was unable to find the event loop for new tests, see pytest-dev/pytest-asyncio#862
b-rowan pushed a commit to UpstreamDataInc/goosebit that referenced this issue Aug 27, 2024
Update pytest-asyncio because it was unable to find the event loop for new tests, see pytest-dev/pytest-asyncio#862
UpstreamData added a commit to UpstreamDataInc/goosebit that referenced this issue Aug 27, 2024
Update pytest-asyncio because it was unable to find the event loop for new tests, see pytest-dev/pytest-asyncio#862
UpstreamData added a commit to UpstreamDataInc/goosebit that referenced this issue Aug 27, 2024
Update pytest-asyncio because it was unable to find the event loop for new tests, see pytest-dev/pytest-asyncio#862
UpstreamData added a commit to UpstreamDataInc/goosebit that referenced this issue Aug 27, 2024
Update pytest-asyncio because it was unable to find the event loop for new tests, see pytest-dev/pytest-asyncio#862
b-rowan pushed a commit to UpstreamDataInc/goosebit that referenced this issue Aug 28, 2024
Update pytest-asyncio because it was unable to find the event loop for new tests, see pytest-dev/pytest-asyncio#862
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants