diff --git a/changelog.d/1298.changed.rst b/changelog.d/1298.changed.rst index 49f83c83..1f3b5d1e 100644 --- a/changelog.d/1298.changed.rst +++ b/changelog.d/1298.changed.rst @@ -1 +1 @@ -Improved the readability of the warning message that is displayed when ``asyncio_default_fixture_loop_scope`` is unset +The default value of ``asyncio_default_fixture_loop_scope`` is now ``function``. The deprecated unset behavior and warning have been removed. diff --git a/changelog.d/924.changed.rst b/changelog.d/924.changed.rst new file mode 100644 index 00000000..1f3b5d1e --- /dev/null +++ b/changelog.d/924.changed.rst @@ -0,0 +1 @@ +The default value of ``asyncio_default_fixture_loop_scope`` is now ``function``. The deprecated unset behavior and warning have been removed. diff --git a/docs/how-to-guides/migrate_from_0_21.rst b/docs/how-to-guides/migrate_from_0_21.rst index a244ad1f..4faadc7c 100644 --- a/docs/how-to-guides/migrate_from_0_21.rst +++ b/docs/how-to-guides/migrate_from_0_21.rst @@ -14,4 +14,4 @@ Go through all re-implemented *event_loop* fixtures in your test suite one by on 1. For all tests and fixtures affected by the re-implemented *event_loop* fixture, configure the *loop_scope* for async tests and fixtures to match the *event_loop* fixture scope. This can be done for each test and fixture individually using either the ``pytest.mark.asyncio(loop_scope="…")`` marker for async tests or ``@pytest_asyncio.fixture(loop_scope="…")`` for async fixtures. Alternatively, you can set the default loop scope for fixtures using the :ref:`asyncio_default_fixture_loop_scope ` configuration option. Snippets to mark all tests with the same *asyncio* marker, thus sharing the same loop scope, are present in the how-to section of the documentation. Depending on the homogeneity of your test suite, you may want a mixture of explicit decorators and default settings. 2. Remove the re-implemented *event_loop* fixture. -If you haven't set the *asyncio_default_fixture_loop_scope* configuration option, yet, set it to *function* to silence the deprecation warning. +The *asyncio_default_fixture_loop_scope* configuration option now defaults to *function* when unset. diff --git a/docs/how-to-guides/migrate_from_0_23.rst b/docs/how-to-guides/migrate_from_0_23.rst index 280b0a80..1e1743df 100644 --- a/docs/how-to-guides/migrate_from_0_23.rst +++ b/docs/how-to-guides/migrate_from_0_23.rst @@ -6,5 +6,5 @@ How to migrate from pytest-asyncio v0.23 The following steps assume that your test suite has no re-implementations of the *event_loop* fixture, nor explicit fixtures requests for it. If this isn't the case, please follow the :ref:`migration guide for pytest-asyncio v0.21. ` 1. Explicitly set the *loop_scope* of async fixtures by replacing occurrences of ``@pytest.fixture(scope="…")`` and ``@pytest_asyncio.fixture(scope="…")`` with ``@pytest_asyncio.fixture(loop_scope="…", scope="…")`` such that *loop_scope* and *scope* are the same. If you use auto mode, resolve all import errors from missing imports of *pytest_asyncio*. If your async fixtures all use the same *loop_scope*, you may choose to set the *asyncio_default_fixture_loop_scope* configuration option to that loop scope, instead. -2. If you haven't set *asyncio_default_fixture_loop_scope*, set it to *function* to address the deprecation warning about the unset configuration option. +2. The *asyncio_default_fixture_loop_scope* configuration option now defaults to *function* when unset. 3. Change all occurrences of ``pytest.mark.asyncio(scope="…")`` to ``pytest.mark.asyncio(loop_scope="…")`` to address the deprecation warning about the *scope* argument to the *asyncio* marker. diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 2fe8db12..afd1d2ed 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -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", @@ -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 @@ -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") @@ -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. diff --git a/tests/test_fixture_loop_scopes.py b/tests/test_fixture_loop_scopes.py index a25e56a0..378dfb1b 100644 --- a/tests/test_fixture_loop_scopes.py +++ b/tests/test_fixture_loop_scopes.py @@ -35,6 +35,29 @@ 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): + pytester.makepyfile(dedent(""" + import pytest + import pytest_asyncio + + @pytest_asyncio.fixture + async def value(): + return 1 + + @pytest.mark.asyncio + async def test_value(value): + assert value == 1 + """)) + + result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "error") + result.assert_outcomes(passed=1) + 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,