Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/924.changed.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The default value of ``asyncio_default_fixture_loop_scope`` is now ``function``. The deprecated unset behavior and warning have been removed.
20 changes: 2 additions & 18 deletions pytest_asyncio/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None
"asyncio_default_fixture_loop_scope",
type="string",
help="default scope of the asyncio event loop used to execute async fixtures",
default=None,
default="function",
)
parser.addini(
"asyncio_default_test_loop_scope",
Expand Down Expand Up @@ -271,16 +271,6 @@ def _collect_hook_loop_factories(
return factories


_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET = """\
The configuration option "asyncio_default_fixture_loop_scope" is unset.
The event loop scope for asynchronous fixtures will default to the "fixture" caching \
scope. Future versions of pytest-asyncio will default the loop scope for asynchronous \
fixtures to "function" scope. Set the default fixture loop scope explicitly in order \
to avoid unexpected behavior in the future. Valid fixture loop scopes are: \
"function", "class", "module", "package", "session"
"""


def _validate_scope(scope: str | None, option_name: str) -> None:
if scope is None:
return
Expand All @@ -295,8 +285,6 @@ def _validate_scope(scope: str | None, option_name: str) -> None:
def pytest_configure(config: Config) -> None:
default_fixture_loop_scope = config.getini("asyncio_default_fixture_loop_scope")
_validate_scope(default_fixture_loop_scope, "asyncio_default_fixture_loop_scope")
if not default_fixture_loop_scope:
warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))

default_test_loop_scope = config.getini("asyncio_default_test_loop_scope")
_validate_scope(default_test_loop_scope, "asyncio_default_test_loop_scope")
Expand Down Expand Up @@ -925,11 +913,7 @@ def pytest_fixture_setup(fixturedef: FixtureDef, request) -> object | None:
if not _is_coroutine_or_asyncgen(fixturedef.func):
return (yield)
default_loop_scope = request.config.getini("asyncio_default_fixture_loop_scope")
loop_scope = (
getattr(fixturedef.func, "_loop_scope", None)
or default_loop_scope
or fixturedef.scope
)
loop_scope = getattr(fixturedef.func, "_loop_scope", None) or default_loop_scope
runner_fixture_id = f"_{loop_scope}_scoped_runner"
runner = request.getfixturevalue(runner_fixture_id)
# Prevent the runner closing before the fixture's async teardown.
Expand Down
33 changes: 33 additions & 0 deletions tests/test_fixture_loop_scopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,39 @@ async def test_runs_in_same_loop_as_fixture(fixture):
result.assert_outcomes(passed=1)


def test_default_fixture_loop_scope_is_function_when_unset(pytester: Pytester):
Comment thread
SahilArchitect marked this conversation as resolved.
pytester.makepyfile(dedent("""
import asyncio
import pytest
import pytest_asyncio

fixture_loops = []

@pytest_asyncio.fixture
async def fixture_loop():
loop = asyncio.get_running_loop()
fixture_loops.append(loop)
return loop

@pytest.mark.asyncio
async def test_fixture_uses_function_loop_scope(fixture_loop):
assert asyncio.get_running_loop() is fixture_loop

@pytest.mark.asyncio
async def test_fixture_uses_new_function_loop(fixture_loop):
assert asyncio.get_running_loop() is fixture_loop
assert fixture_loops[0] is not fixture_loops[1]
"""))

result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "error")
result.assert_outcomes(passed=2)
result.stdout.fnmatch_lines(
[
"*asyncio_default_fixture_loop_scope=function*",
]
)


@pytest.mark.parametrize("default_loop_scope", ("function", "module", "session"))
def test_default_loop_scope_config_option_changes_fixture_loop_scope(
pytester: Pytester,
Expand Down
Loading