diff --git a/docs/reference/changelog.rst b/docs/reference/changelog.rst index 77cf3451..285aadf5 100644 --- a/docs/reference/changelog.rst +++ b/docs/reference/changelog.rst @@ -2,6 +2,10 @@ Changelog ========= +0.25.0 (UNRELEASED) +=================== +- Deprecated: Added warning when asyncio test requests async ``@pytest.fixture`` in strict mode. This will become an error in a future version of flake8-asyncio. `#979 `_ + 0.24.0 (2024-08-22) =================== - BREAKING: Updated minimum supported pytest version to v8.2.0 diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index b4e6ab33..0261d12e 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -880,7 +880,32 @@ def pytest_pyfunc_call(pyfuncitem: Function) -> object | None: """ if pyfuncitem.get_closest_marker("asyncio") is not None: if isinstance(pyfuncitem, PytestAsyncioFunction): - pass + asyncio_mode = _get_asyncio_mode(pyfuncitem.config) + for fixname, fixtures in pyfuncitem._fixtureinfo.name2fixturedefs.items(): + # name2fixturedefs is a dict between fixture name and a list of matching + # fixturedefs. The last entry in the list is closest and the one used. + func = fixtures[-1].func + if ( + _is_coroutine_or_asyncgen(func) + and not _is_asyncio_fixture_function(func) + and asyncio_mode == Mode.STRICT + ): + warnings.warn( + PytestDeprecationWarning( + f"asyncio test {pyfuncitem.name!r} requested async " + "@pytest.fixture " + f"{fixname!r} in strict mode. " + "You might want to use @pytest_asyncio.fixture or switch " + "to auto mode. " + "This will become an error in future versions of " + "flake8-asyncio." + ), + stacklevel=1, + ) + # no stacklevel points at the users code, so we set stacklevel=1 + # so it at least indicates that it's the plugin complaining. + # Pytest gives the test file & name in the warnings summary at least + else: pyfuncitem.warn( pytest.PytestWarning( diff --git a/tests/modes/test_strict_mode.py b/tests/modes/test_strict_mode.py index c5a7351a..52cbb251 100644 --- a/tests/modes/test_strict_mode.py +++ b/tests/modes/test_strict_mode.py @@ -124,3 +124,90 @@ async def test_anything(any_fixture): "*coroutine 'any_fixture' was never awaited*", ], ) + + +def test_strict_mode_marked_test_unmarked_fixture_warning(pytester: Pytester): + pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function") + pytester.makepyfile( + dedent( + """\ + import pytest + + # Not using pytest_asyncio.fixture + @pytest.fixture() + async def any_fixture(): + pass + + @pytest.mark.asyncio + async def test_anything(any_fixture): + # suppress unawaited coroutine warning + try: + any_fixture.send(None) + except StopIteration: + pass + """ + ) + ) + result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default") + result.assert_outcomes(passed=1, failed=0, skipped=0, warnings=1) + result.stdout.fnmatch_lines( + [ + "*warnings summary*", + ( + "test_strict_mode_marked_test_unmarked_fixture_warning.py::" + "test_anything" + ), + ( + "*/pytest_asyncio/plugin.py:*: PytestDeprecationWarning: " + "asyncio test 'test_anything' requested async " + "@pytest.fixture 'any_fixture' in strict mode. " + "You might want to use @pytest_asyncio.fixture or switch to " + "auto mode. " + "This will become an error in future versions of flake8-asyncio." + ), + ], + ) + + +# autouse is not handled in any special way currently +def test_strict_mode_marked_test_unmarked_autouse_fixture_warning(pytester: Pytester): + pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function") + pytester.makepyfile( + dedent( + """\ + import pytest + + # Not using pytest_asyncio.fixture + @pytest.fixture(autouse=True) + async def any_fixture(): + pass + + @pytest.mark.asyncio + async def test_anything(any_fixture): + # suppress unawaited coroutine warning + try: + any_fixture.send(None) + except StopIteration: + pass + """ + ) + ) + result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default") + result.assert_outcomes(passed=1, warnings=1) + result.stdout.fnmatch_lines( + [ + "*warnings summary*", + ( + "test_strict_mode_marked_test_unmarked_autouse_fixture_warning.py::" + "test_anything" + ), + ( + "*/pytest_asyncio/plugin.py:*: PytestDeprecationWarning: " + "*asyncio test 'test_anything' requested async " + "@pytest.fixture 'any_fixture' in strict mode. " + "You might want to use @pytest_asyncio.fixture or switch to " + "auto mode. " + "This will become an error in future versions of flake8-asyncio." + ), + ], + )