From 9aa2fa5aec295998db4a67d2927db4c631e8b845 Mon Sep 17 00:00:00 2001 From: JingHao-Leon <102573344+JingHao-Leon@users.noreply.github.com> Date: Mon, 19 Oct 2026 18:21:00 +0800 Subject: [PATCH] Validate asyncio marker loop_scope via _validate_scope The marker's loop_scope was checked with a bare assert, so an invalid value surfaced as AssertionError: assert 'x' in {'class', 'function', ...}. Use the helper that already validates the two ini options instead, so the reported message names the argument and lists the valid scopes. --- changelog.d/1584.fixed.rst | 1 + pytest_asyncio/plugin.py | 3 +-- tests/test_fixture_loop_scopes.py | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 changelog.d/1584.fixed.rst diff --git a/changelog.d/1584.fixed.rst b/changelog.d/1584.fixed.rst new file mode 100644 index 00000000..1e146fc3 --- /dev/null +++ b/changelog.d/1584.fixed.rst @@ -0,0 +1 @@ +Fixed an invalid ``loop_scope`` in the ``asyncio`` marker being reported as a bare ``AssertionError`` exposing a Python set repr, instead of a usage error that names the argument and lists the valid scopes. diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 38b75e41..e99a8d03 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -979,8 +979,7 @@ def _parse_asyncio_marker( scope = asyncio_marker.kwargs.get("loop_scope") or asyncio_marker.kwargs.get( "scope" ) - if scope is not None: - assert scope in {"function", "class", "module", "package", "session"} + _validate_scope(scope, "loop_scope") marker_value = asyncio_marker.kwargs.get("loop_factories") if marker_value is None: return scope, None diff --git a/tests/test_fixture_loop_scopes.py b/tests/test_fixture_loop_scopes.py index a25e56a0..a051b8a1 100644 --- a/tests/test_fixture_loop_scopes.py +++ b/tests/test_fixture_loop_scopes.py @@ -126,3 +126,23 @@ def test_invalid_default_fixture_loop_scope_raises_error(pytester: Pytester): "function, class, module, package, session." ] ) + + +def test_invalid_marker_loop_scope_raises_error(pytester: Pytester): + pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function") + pytester.makepyfile("""\ + import pytest + + @pytest.mark.asyncio(loop_scope="invalid_scope") + async def test_invalid_loop_scope(): + pass + """) + result = pytester.runpytest("--assert=plain") + # The exception class is rendered as pytest.UsageError on newer pytest and as + # _pytest.config.exceptions.UsageError on the oldest supported version. + result.stdout.fnmatch_lines( + [ + "*UsageError: 'invalid_scope' is not a valid loop_scope. " + "Valid scopes are: function, class, module, package, session." + ] + )