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

Config for default test loop_scope? #934

Closed
BryceCicada opened this issue Sep 5, 2024 · 2 comments
Closed

Config for default test loop_scope? #934

BryceCicada opened this issue Sep 5, 2024 · 2 comments
Milestone

Comments

@BryceCicada
Copy link

pytest-asyncio v0.24 supports independent event-loop scopes and fixture caching scopes. This is great, thank you. However, I had some confusion while working with this. I thought I'd share in case there's an elegant solution I've not spotted.

The following works fine:

import asyncio
import pytest
import pytest_asyncio

loop: asyncio.AbstractEventLoop | None = None


@pytest_asyncio.fixture(loop_scope="session")
async def loop_fixture():
    global loop
    loop = asyncio.get_running_loop()


@pytest_asyncio.fixture(loop_scope="session", scope="function")
async def another_fixture():
    return "foo"


@pytest.mark.asyncio(loop_scope="session")
async def test_a(loop_fixture, another_fixture):
    global loop
    assert loop == asyncio.get_running_loop()
    assert another_fixture == "foo"

and with a minor change I've convinced myself that another_fixture really is function-scoped. All good.

However, if I have pyproject.toml containing:

[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "session"

my initial (hopeful) expectation was that I would not need to write loop_scope="session" everywhere, but this is mistaken:

import asyncio
import pytest
import pytest_asyncio

loop: asyncio.AbstractEventLoop | None = None


@pytest_asyncio.fixture
async def loop_fixture():
    global loop
    loop = asyncio.get_running_loop()


@pytest_asyncio.fixture(scope="function")
async def another_fixture():
    return "foo"


@pytest.mark.asyncio
async def test_a(loop_fixture, another_fixture):
    global loop
    assert loop == asyncio.get_running_loop()
    assert another_fixture == "foo"

with error:

E   pytest_asyncio.plugin.MultipleEventLoopsRequestedError: Multiple asyncio event loops with different scopes have been requested

Of course, the solution is to omit loop_scope="session" only the fixtures, but keep it on the test function itself like:

@pytest.mark.asyncio(loop_scope="session")
async def test_a(loop_fixture, another_fixture):
    ...

but in a suite of many tests, it's boilerplate.

I've understood asyncio_default_fixture_loop_scope was intended to relieve such boilerplate on the fixtures, but is there something similar possible for the tests themselves? I know I could write a hook to add this marker to the tests, but my gut feeling says this magic would confuse later. On the other hand, I could imagine some config like asyncio_default_test_loop_scope... is there something neat I've missed?

@BryceCicada
Copy link
Author

I see this is already under thought at #793.

@BryceCicada
Copy link
Author

I've gone with:

  • A hook to add local_scope="session" to tests, and additionally
  • Added config asyncio_mode = "auto" so I can remove @pytest.mark.asyncio from tests to further reduce the boilerplate.

I'll keep an eye on #793. Closing this.

@seifertm seifertm added this to the v0.24 milestone Sep 19, 2024
@seifertm seifertm closed this as not planned Won't fix, can't repro, duplicate, stale Sep 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants