From 6728ec5606dd7e2eb70ef64972f97eab061f95e2 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Thu, 31 Oct 2024 16:48:11 +0100 Subject: [PATCH 01/18] Raise error if sync test relies on async fixture, and warn if the fixture is autouse. --- src/_pytest/fixtures.py | 36 +++++++++++++++- testing/acceptance_test.py | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 6b882fa351..499d065c4a 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -73,6 +73,7 @@ from _pytest.scope import _ScopeName from _pytest.scope import HIGH_SCOPES from _pytest.scope import Scope +from _pytest.warning_types import PytestRemovedIn9Warning if sys.version_info < (3, 11): @@ -575,6 +576,7 @@ def _get_active_fixturedef( # The are no fixtures with this name applicable for the function. if not fixturedefs: raise FixtureLookupError(argname, self) + # A fixture may override another fixture with the same name, e.g. a # fixture in a module can override a fixture in a conftest, a fixture in # a class can override a fixture in the module, and so on. @@ -593,6 +595,32 @@ def _get_active_fixturedef( raise FixtureLookupError(argname, self) fixturedef = fixturedefs[index] + if not inspect.iscoroutinefunction(self.function) and ( + inspect.iscoroutinefunction(fixturedef.func) + or inspect.isasyncgenfunction(fixturedef.func) + ): + if fixturedef._autouse: + warnings.warn( + PytestRemovedIn9Warning( + "Sync test requested an async fixture with autouse=True. " + "If you intended to use the fixture you may want to make the " + "test asynchronous. If you did not intend to use it you should " + "restructure your test setup. " + "This will turn into an error in pytest 9." + ), + stacklevel=3, + ) + else: + raise FixtureLookupError( + argname, + self, + ( + "ERROR: Sync test requested async fixture. " + "You may want to make the test asynchronous and run it with " + "a suitable async framework test plugin." + ), + ) + # Prepare a SubRequest object for calling the fixture. try: callspec = self._pyfuncitem.callspec @@ -805,7 +833,7 @@ def formatrepr(self) -> FixtureLookupErrorRepr: stack = [self.request._pyfuncitem.obj] stack.extend(map(lambda x: x.func, self.fixturestack)) msg = self.msg - if msg is not None: + if msg is not None and len(stack) > 1: # The last fixture raise an error, let's present # it at the requesting side. stack = stack[:-1] @@ -959,6 +987,8 @@ def __init__( ids: tuple[object | None, ...] | Callable[[Any], object | None] | None = None, *, _ispytest: bool = False, + # only used to emit a deprecationwarning, can be removed in pytest9 + _autouse: bool = False, ) -> None: check_ispytest(_ispytest) # The "base" node ID for the fixture. @@ -1005,6 +1035,9 @@ def __init__( self.cached_result: _FixtureCachedResult[FixtureValue] | None = None self._finalizers: Final[list[Callable[[], object]]] = [] + # only used to emit a deprecationwarning, can be removed in pytest9 + self._autouse = _autouse + @property def scope(self) -> _ScopeName: """Scope string, one of "function", "class", "module", "package", "session".""" @@ -1666,6 +1699,7 @@ def _register_fixture( params=params, ids=ids, _ispytest=True, + _autouse=autouse, ) faclist = self._arg2fixturedefs.setdefault(name, []) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 7a8d871144..0437cae404 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1286,6 +1286,93 @@ def test_3(): result.assert_outcomes(failed=3) +def test_error_on_sync_test_async_fixture(pytester: Pytester) -> None: + pytester.makepyfile( + test_sync=""" + import pytest + + @pytest.fixture + async def async_fixture(): + ... + + def test_foo(async_fixture): + ... + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines( + [ + ( + "*ERROR: Sync test requested async fixture. " + "You may want to make the test asynchronous and run it with " + "a suitable async framework test plugin.*" + ), + "*ERROR test_sync.py::test_foo*", + ] + ) + result.assert_outcomes(errors=1) + + +def test_error_on_sync_test_async_fixture_gen(pytester: Pytester) -> None: + pytester.makepyfile( + test_sync=""" + import pytest + + @pytest.fixture + async def async_fixture(): + yield + + def test_foo(async_fixture): + ... + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines( + [ + ( + "*ERROR: Sync test requested async fixture. " + "You may want to make the test asynchronous and run it with " + "a suitable async framework test plugin.*" + ), + "*ERROR test_sync.py::test_foo*", + ] + ) + result.assert_outcomes(errors=1) + + +def test_warning_on_sync_test_async_autouse_fixture(pytester: Pytester) -> None: + pytester.makepyfile( + test_sync=""" + import pytest + + @pytest.fixture(autouse=True) + async def async_fixture(): + ... + + # We explicitly request the fixture to be able to + # suppress the RuntimeWarning for unawaited coroutine. + def test_foo(async_fixture): + try: + async_fixture.send(None) + except StopIteration: + pass + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines( + [ + ( + "*Sync test requested an async fixture with autouse=True. " + "If you intended to use the fixture you may want to make the " + "test asynchronous. If you did not intend to use it you should " + "restructure your test setup. " + "This will turn into an error in pytest 9.*" + ), + ] + ) + result.assert_outcomes(passed=1) + + def test_pdb_can_be_rewritten(pytester: Pytester) -> None: pytester.makepyfile( **{ From 8e100ea2c70ea7252141902af819a7aae44a53c1 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Fri, 1 Nov 2024 11:56:59 +0100 Subject: [PATCH 02/18] fix tests --- src/_pytest/fixtures.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 499d065c4a..da6625fb7e 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -595,9 +595,16 @@ def _get_active_fixturedef( raise FixtureLookupError(argname, self) fixturedef = fixturedefs[index] - if not inspect.iscoroutinefunction(self.function) and ( - inspect.iscoroutinefunction(fixturedef.func) - or inspect.isasyncgenfunction(fixturedef.func) + # Check for attempted use of an async fixture by a sync test + # `self.scope` here is not the scope of the requested fixture, but the scope of + # the requester. + if ( + self.scope == "function" + and not inspect.iscoroutinefunction(self._pyfuncitem.obj) + and ( + inspect.iscoroutinefunction(fixturedef.func) + or inspect.isasyncgenfunction(fixturedef.func) + ) ): if fixturedef._autouse: warnings.warn( From 283db4ed9f803c6b1f19b8920ed8b01cfda20b59 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Fri, 1 Nov 2024 12:15:23 +0100 Subject: [PATCH 03/18] add changelog --- changelog/10839.deprecation.rst | 1 + changelog/10839.improvement.rst | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog/10839.deprecation.rst create mode 100644 changelog/10839.improvement.rst diff --git a/changelog/10839.deprecation.rst b/changelog/10839.deprecation.rst new file mode 100644 index 0000000000..c062819166 --- /dev/null +++ b/changelog/10839.deprecation.rst @@ -0,0 +1 @@ +Synchronous tests that request an asynchronous fixture with ``autouse=True`` will now give a DeprecationWarning. diff --git a/changelog/10839.improvement.rst b/changelog/10839.improvement.rst new file mode 100644 index 0000000000..0a382053c8 --- /dev/null +++ b/changelog/10839.improvement.rst @@ -0,0 +1 @@ +Synchronous tests that request asynchronous fixtures will now error, instead of silently accepting an unawaited coroutine object as the fixture value. From 5beab07de39dc4dd8a8db289f934288ae5be6bfc Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 6 Nov 2024 14:02:25 +0100 Subject: [PATCH 04/18] improve warning message. Make it warn regardless of autouse or not. Add section to deprecations.rst --- changelog/10839.deprecation.rst | 2 +- changelog/10839.improvement.rst | 1 - doc/en/deprecations.rst | 55 +++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/_pytest/fixtures.py | 19 +++++++----- testing/acceptance_test.py | 40 +++++++++++++++--------- 6 files changed, 93 insertions(+), 26 deletions(-) delete mode 100644 changelog/10839.improvement.rst diff --git a/changelog/10839.deprecation.rst b/changelog/10839.deprecation.rst index c062819166..78ad4e118e 100644 --- a/changelog/10839.deprecation.rst +++ b/changelog/10839.deprecation.rst @@ -1 +1 @@ -Synchronous tests that request an asynchronous fixture with ``autouse=True`` will now give a DeprecationWarning. +Synchronous tests that request an asynchronous fixture will now give a DeprecationWarning. This will introduce warnings in several pytest plugins that handle async tests/fixtures and for some users with custom setups. For guidance on how to manage this see :ref:`sync-test-async-fixture`. diff --git a/changelog/10839.improvement.rst b/changelog/10839.improvement.rst deleted file mode 100644 index 0a382053c8..0000000000 --- a/changelog/10839.improvement.rst +++ /dev/null @@ -1 +0,0 @@ -Synchronous tests that request asynchronous fixtures will now error, instead of silently accepting an unawaited coroutine object as the fixture value. diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index e55f0d71c2..b384f01dfa 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -15,6 +15,61 @@ Below is a complete list of all pytest features which are considered deprecated. :class:`~pytest.PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters `. +.. _sync-test-async-fixture: + +sync test depending on async fixture +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 8.4 + +Pytest has for a long time given an error when encountering an asynchronous test function, prompting the user to install +a plugin that can handle it. It has not given any errors if you have an asynchronous fixture that's depended on by a +synchronous test. This is a problem even if you do have a plugin installed for handling async tests, as they may require +special decorators for async fixtures to be handled, and some may not robustly handle if a user accidentally requests an +async fixture from their sync tests. Fixture values being cached can make this even more unintuitive, where everything will +"work" if the fixture is first requested by an async test, and then requested by a synchronous test. + +Unfortunately there is no 100% reliable method of identifying when a user has made a mistake, versus when they expect an +unawaited object from their fixture that they will handle - either on their own, or by a plugin. To suppress this warning +when you in fact did intend to handle this you can wrap your async fixture in a synchronous fixture: + +.. code-block:: python + + import asyncio + import pytest + + + @pytest.fixture + async def unawaited_fixture(): + return 1 + + + def test_foo(unawaited_fixture): + assert 1 == asyncio.run(unawaited_fixture) + +should be changed to + + +.. code-block:: python + + import asyncio + import pytest + + + @pytest.fixture + def unawaited_fixture(): + async def inner_fixture(): + return 1 + + return inner_fixture() + + + def test_foo(unawaited_fixture): + assert 1 == asyncio.run(unawaited_fixture) + +If a user has an async fixture with ``autouse=True`` in their ``conftest.py``, or in a file where they also have synchronous tests, they will also get this warning. We strongly recommend against this practice, and they should restructure their testing infrastructure so the fixture is synchronous or to separate the fixture from their synchronous tests. Plugins that handle async may want to introduce helpers to make that easier in scenarios where that might be wanted, e.g. if setting up a database in an asynchronous way, or the user may opt to make their test async even though it might not strictly need to be. + + .. _import-or-skip-import-error: ``pytest.importorskip`` default behavior regarding :class:`ImportError` diff --git a/pyproject.toml b/pyproject.toml index caeb4bf7f8..b023f78856 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -308,7 +308,7 @@ disable = [ ] [tool.codespell] -ignore-words-list = "afile,asser,assertio,feld,hove,ned,noes,notin,paramete,parth,socio-economic,tesults,varius,wil" +ignore-words-list = "afile,asend,asser,assertio,feld,hove,ned,noes,notin,paramete,parth,socio-economic,tesults,varius,wil" skip = "*/plugin_list.rst" write-changes = true diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index da6625fb7e..4b45489cd9 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -609,23 +609,26 @@ def _get_active_fixturedef( if fixturedef._autouse: warnings.warn( PytestRemovedIn9Warning( - "Sync test requested an async fixture with autouse=True. " + f"Sync test {self._pyfuncitem.name!r} requested async fixture " + f"{argname!r} with autouse=True. " "If you intended to use the fixture you may want to make the " - "test asynchronous. If you did not intend to use it you should " + "test asynchronous or the fixture synchronous. " + "If you did not intend to use it you should " "restructure your test setup. " "This will turn into an error in pytest 9." ), stacklevel=3, ) else: - raise FixtureLookupError( - argname, - self, - ( - "ERROR: Sync test requested async fixture. " + warnings.warn( + PytestRemovedIn9Warning( + f"Sync test {self._pyfuncitem.name!r} requested async fixture " + f"{argname!r}. " "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin." + "a suitable async framework test plugin, or make the fixture synchronous. " + "This will turn into an error in pytest 9." ), + stacklevel=3, ) # Prepare a SubRequest object for calling the fixture. diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 0437cae404..699ad4797b 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1296,21 +1296,26 @@ async def async_fixture(): ... def test_foo(async_fixture): - ... + # suppress unawaited coroutine warning + try: + async_fixture.send(None) + except StopIteration: + pass """ ) result = pytester.runpytest() result.stdout.fnmatch_lines( [ ( - "*ERROR: Sync test requested async fixture. " + "*Sync test 'test_foo' requested async fixture " + "'async_fixture'. " "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin.*" + "a suitable async framework test plugin, or make the fixture synchronous. " + "This will turn into an error in pytest 9." ), - "*ERROR test_sync.py::test_foo*", ] ) - result.assert_outcomes(errors=1) + result.assert_outcomes(passed=1, warnings=1) def test_error_on_sync_test_async_fixture_gen(pytester: Pytester) -> None: @@ -1323,21 +1328,26 @@ async def async_fixture(): yield def test_foo(async_fixture): - ... + # suppress unawaited coroutine warning + try: + async_fixture.asend(None) + except StopIteration: + pass """ ) result = pytester.runpytest() result.stdout.fnmatch_lines( [ ( - "*ERROR: Sync test requested async fixture. " + "*Sync test 'test_foo' requested async fixture " + "'async_fixture'. " "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin.*" + "a suitable async framework test plugin, or make the fixture synchronous. " + "This will turn into an error in pytest 9." ), - "*ERROR test_sync.py::test_foo*", ] ) - result.assert_outcomes(errors=1) + result.assert_outcomes(passed=1, warnings=1) def test_warning_on_sync_test_async_autouse_fixture(pytester: Pytester) -> None: @@ -1362,11 +1372,11 @@ def test_foo(async_fixture): result.stdout.fnmatch_lines( [ ( - "*Sync test requested an async fixture with autouse=True. " - "If you intended to use the fixture you may want to make the " - "test asynchronous. If you did not intend to use it you should " - "restructure your test setup. " - "This will turn into an error in pytest 9.*" + "*Sync test 'test_foo' requested async fixture " + "'async_fixture' with autouse=True. " + "You may want to make the test asynchronous and run it with " + "a suitable async framework test plugin, or make the fixture synchronous. " + "This will turn into an error in pytest 9." ), ] ) From 0de5302bfde78747ca6b4d468d7d60658f43307c Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 6 Nov 2024 14:12:12 +0100 Subject: [PATCH 05/18] fix test --- testing/acceptance_test.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 699ad4797b..a7a9afedbc 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1286,7 +1286,7 @@ def test_3(): result.assert_outcomes(failed=3) -def test_error_on_sync_test_async_fixture(pytester: Pytester) -> None: +def test_warning_on_sync_test_async_fixture(pytester: Pytester) -> None: pytester.makepyfile( test_sync=""" import pytest @@ -1318,7 +1318,7 @@ def test_foo(async_fixture): result.assert_outcomes(passed=1, warnings=1) -def test_error_on_sync_test_async_fixture_gen(pytester: Pytester) -> None: +def test_warning_on_sync_test_async_fixture_gen(pytester: Pytester) -> None: pytester.makepyfile( test_sync=""" import pytest @@ -1374,13 +1374,15 @@ def test_foo(async_fixture): ( "*Sync test 'test_foo' requested async fixture " "'async_fixture' with autouse=True. " - "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin, or make the fixture synchronous. " + "If you intended to use the fixture you may want to make the " + "test asynchronous or the fixture synchronous. " + "If you did not intend to use it you should " + "restructure your test setup. " "This will turn into an error in pytest 9." ), ] ) - result.assert_outcomes(passed=1) + result.assert_outcomes(passed=1, warnings=1) def test_pdb_can_be_rewritten(pytester: Pytester) -> None: From 1891fedbb1e37c9e61cbdcdaf2d05f5493a24d2c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 6 Nov 2024 13:30:49 -0300 Subject: [PATCH 06/18] Rename changelog entries to 'breaking' (#12942) Follow up to https://github.com/pytest-dev/pytest/pull/12346. --- changelog/{11372.improvement.rst => 11372.breaking.rst} | 0 changelog/{12346.misc.rst => 12346.breaking.rst} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename changelog/{11372.improvement.rst => 11372.breaking.rst} (100%) rename changelog/{12346.misc.rst => 12346.breaking.rst} (100%) diff --git a/changelog/11372.improvement.rst b/changelog/11372.breaking.rst similarity index 100% rename from changelog/11372.improvement.rst rename to changelog/11372.breaking.rst diff --git a/changelog/12346.misc.rst b/changelog/12346.breaking.rst similarity index 100% rename from changelog/12346.misc.rst rename to changelog/12346.breaking.rst From 6b9de2ab2e52181102bdaf9acbaf7815eb078ed2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 23:01:37 +0000 Subject: [PATCH 07/18] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.9 → v0.7.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.9...v0.7.2) - [github.com/adamchainz/blacken-docs: 1.19.0 → 1.19.1](https://github.com/adamchainz/blacken-docs/compare/1.19.0...1.19.1) - [github.com/pre-commit/mirrors-mypy: v1.11.2 → v1.13.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.2...v1.13.0) - [github.com/tox-dev/pyproject-fmt: 2.3.1 → v2.5.0](https://github.com/tox-dev/pyproject-fmt/compare/2.3.1...v2.5.0) - [github.com/asottile/pyupgrade: v3.18.0 → v3.19.0](https://github.com/asottile/pyupgrade/compare/v3.18.0...v3.19.0) [mypy] Remove useless noqa, add noqa for new false positives Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- .pre-commit-config.yaml | 11 ++++++----- pyproject.toml | 3 ++- src/_pytest/_io/pprint.py | 6 +++--- src/_pytest/capture.py | 6 ++++-- testing/test_runner.py | 4 ++-- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 096228acf9..04971cf9fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.6.9" + rev: "v0.7.2" hooks: - id: ruff args: ["--fix"] @@ -12,7 +12,7 @@ repos: - id: end-of-file-fixer - id: check-yaml - repo: https://github.com/adamchainz/blacken-docs - rev: 1.19.0 + rev: 1.19.1 hooks: - id: blacken-docs additional_dependencies: [black==24.1.1] @@ -28,7 +28,7 @@ repos: hooks: - id: python-use-type-annotations - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 + rev: v1.13.0 hooks: - id: mypy files: ^(src/|testing/|scripts/) @@ -44,13 +44,13 @@ repos: # on <3.11 - exceptiongroup>=1.0.0rc8 - repo: https://github.com/tox-dev/pyproject-fmt - rev: "2.3.1" + rev: "v2.5.0" hooks: - id: pyproject-fmt # https://pyproject-fmt.readthedocs.io/en/latest/#calculating-max-supported-python-version additional_dependencies: ["tox>=4.9"] - repo: https://github.com/asottile/pyupgrade - rev: v3.18.0 + rev: v3.19.0 hooks: - id: pyupgrade stages: [manual] @@ -62,6 +62,7 @@ repos: language: system types: [python] args: ["-rn", "-sn", "--fail-on=I"] + require_serial: true stages: [manual] - id: rst name: rst diff --git a/pyproject.toml b/pyproject.toml index b023f78856..da47e4b045 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ dependencies = [ "exceptiongroup>=1.0.0rc8; python_version<'3.11'", "iniconfig", "packaging", - "pluggy<2,>=1.5", + "pluggy>=1.5,<2", "tomli>=1; python_version<'3.11'", ] optional-dependencies.dev = [ @@ -275,6 +275,7 @@ disable = [ "too-many-lines", "too-many-locals", "too-many-nested-blocks", + "too-many-positional-arguments", "too-many-public-methods", "too-many-return-statements", # disabled in ruff "too-many-statements", # disabled in ruff diff --git a/src/_pytest/_io/pprint.py b/src/_pytest/_io/pprint.py index fc29989be0..7a6433d912 100644 --- a/src/_pytest/_io/pprint.py +++ b/src/_pytest/_io/pprint.py @@ -111,15 +111,15 @@ def _format( p(self, object, stream, indent, allowance, context, level + 1) context.remove(objid) elif ( - _dataclasses.is_dataclass(object) # type:ignore[unreachable] + _dataclasses.is_dataclass(object) and not isinstance(object, type) - and object.__dataclass_params__.repr + and object.__dataclass_params__.repr # type:ignore[attr-defined] and # Check dataclass has generated repr method. hasattr(object.__repr__, "__wrapped__") and "__create_fn__" in object.__repr__.__wrapped__.__qualname__ ): - context.add(objid) # type:ignore[unreachable] + context.add(objid) self._pprint_dataclass( object, stream, indent, allowance, context, level + 1 ) diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 506c0b3d28..2ac3b6bbc7 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -15,6 +15,7 @@ from typing import Any from typing import AnyStr from typing import BinaryIO +from typing import cast from typing import Final from typing import final from typing import Generator @@ -177,7 +178,8 @@ def name(self) -> str: def mode(self) -> str: # TextIOWrapper doesn't expose a mode, but at least some of our # tests check it. - return self.buffer.mode.replace("b", "") + assert hasattr(self.buffer, "mode") + return cast(str, self.buffer.mode.replace("b", "")) class CaptureIO(io.TextIOWrapper): @@ -550,7 +552,7 @@ def snap(self) -> bytes: res = self.tmpfile.buffer.read() self.tmpfile.seek(0) self.tmpfile.truncate() - return res + return res # type: ignore[return-value] def writeorg(self, data: bytes) -> None: """Write to original file descriptor.""" diff --git a/testing/test_runner.py b/testing/test_runner.py index 0d9facdcd7..0245438a47 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -137,8 +137,8 @@ def raiser(exc): ss.teardown_exact(None) mod, func = e.value.exceptions assert isinstance(mod, KeyError) - assert isinstance(func.exceptions[0], TypeError) # type: ignore - assert isinstance(func.exceptions[1], ValueError) # type: ignore + assert isinstance(func.exceptions[0], TypeError) + assert isinstance(func.exceptions[1], ValueError) def test_cached_exception_doesnt_get_longer(self, pytester: Pytester) -> None: """Regression test for #12204 (the "BTW" case).""" From 94dd15341a036b0a464992c2be0e48d4a8b9d23c Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Tue, 29 Oct 2024 10:08:27 +0100 Subject: [PATCH 08/18] Upgrade pylint version, activate all extensions --- .pre-commit-config.yaml | 2 +- pyproject.toml | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04971cf9fb..b8e7053e1c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,7 +61,7 @@ repos: entry: pylint language: system types: [python] - args: ["-rn", "-sn", "--fail-on=I"] + args: ["-rn", "-sn", "--fail-on=I", "--enable-all-extentions"] require_serial: true stages: [manual] - id: rst diff --git a/pyproject.toml b/pyproject.toml index da47e4b045..c968b82655 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -200,7 +200,9 @@ disable = [ "arguments-renamed", "assigning-non-slot", "attribute-defined-outside-init", + "bad-builtin", "bad-classmethod-argument", + "bad-dunder-name", "bad-mcs-method-argument", "broad-exception-caught", "broad-exception-raised", @@ -209,25 +211,41 @@ disable = [ "comparison-with-callable", "comparison-with-itself", # PLR0124 from ruff "condition-evals-to-constant", + "consider-alternative-union-syntax", + "confusing-consecutive-elif", + "consider-using-any-or-all", + "consider-using-assignment-expr", "consider-using-dict-items", "consider-using-from-import", "consider-using-f-string", "consider-using-in", + "consider-using-namedtuple-or-dataclass", "consider-using-ternary", + "consider-using-tuple", "consider-using-with", "consider-using-from-import", # not activated by default, PLR0402 disabled in ruff + "consider-ternary-expression", "cyclic-import", + "differing-param-doc", + "docstring-first-line-empty", + "deprecated-argument", + "deprecated-attribute", + "deprecated-class", + "deprecated-typing-alias", + "dict-init-mutate", "disallowed-name", # foo / bar are used often in tests "duplicate-code", "else-if-used", # not activated by default, PLR5501 disabled in ruff "empty-comment", # not activated by default, PLR2044 disabled in ruff "eval-used", + "eq-without-hash", "exec-used", "expression-not-assigned", "fixme", "global-statement", # PLW0603 disabled in ruff "import-error", "import-outside-toplevel", + "import-private-name", "inconsistent-return-statements", "invalid-bool-returned", "invalid-name", @@ -238,8 +256,12 @@ disable = [ "magic-value-comparison", # not activated by default, PLR2004 disabled in ruff "method-hidden", "missing-docstring", + "missing-param-doc", + "missing-raises-doc", "missing-timeout", + "missing-type-doc", "misplaced-bare-raise", # PLE0704 from ruff + "misplaced-comparison-constant", "multiple-statements", # multiple-statements-on-one-line-colon (E701) from ruff "no-else-break", "no-else-continue", @@ -248,6 +270,7 @@ disable = [ "no-member", "no-name-in-module", "no-self-argument", + "no-self-use", "not-an-iterable", "not-callable", "pointless-exception-statement", # https://github.com/pytest-dev/pytest/pull/12379 @@ -260,12 +283,14 @@ disable = [ "redefined-builtin", "redefined-loop-name", # PLW2901 disabled in ruff "redefined-outer-name", + "redefined-variable-type", "reimported", "simplifiable-condition", "simplifiable-if-expression", "singleton-comparison", "superfluous-parens", "super-init-not-called", + "too-complex", "too-few-public-methods", "too-many-ancestors", "too-many-arguments", # disabled in ruff @@ -279,6 +304,7 @@ disable = [ "too-many-public-methods", "too-many-return-statements", # disabled in ruff "too-many-statements", # disabled in ruff + "too-many-try-statements", "try-except-raise", "typevar-name-incorrect-variance", # PLC0105 disabled in ruff "unbalanced-tuple-unpacking", @@ -300,10 +326,12 @@ disable = [ "use-dict-literal", "use-implicit-booleaness-not-comparison", "use-implicit-booleaness-not-len", + "use-set-for-membership", "useless-else-on-loop", # PLC0414 disabled in ruff "useless-import-alias", "useless-return", "using-constant-test", + "while-used", "wrong-import-order", # handled by isort / ruff "wrong-import-position", # handled by isort / ruff ] From b19fd523e18a35dd17bc3ae61a251b73cb940551 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Tue, 29 Oct 2024 10:09:09 +0100 Subject: [PATCH 09/18] [pylint dict-init-mutate] Initialize a dict right off for speed --- pyproject.toml | 1 - src/_pytest/junitxml.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c968b82655..3636ee455a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -232,7 +232,6 @@ disable = [ "deprecated-attribute", "deprecated-class", "deprecated-typing-alias", - "dict-init-mutate", "disallowed-name", # foo / bar are used often in tests "duplicate-code", "else-if-used", # not activated by default, PLR5501 disabled in ruff diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 3a2cb59a6c..efe6f489b4 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -74,10 +74,10 @@ def merge_family(left, right) -> None: left.update(result) -families = {} -families["_base"] = {"testcase": ["classname", "name"]} -families["_base_legacy"] = {"testcase": ["file", "line", "url"]} - +families = { # pylint: disable=dict-init-mutate + "_base": {"testcase": ["classname", "name"]}, + "_base_legacy": {"testcase": ["file", "line", "url"]}, +} # xUnit 1.x inherits legacy attributes. families["xunit1"] = families["_base"].copy() merge_family(families["xunit1"], families["_base_legacy"]) From 987904c13cdd03fd49f46a88738e13f808db99bd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 10 Nov 2024 08:39:36 +0000 Subject: [PATCH 10/18] [automated] Update plugin list (#12950) Co-authored-by: pytest bot --- doc/en/reference/plugin_list.rst | 78 +++++++++++++++++++------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/doc/en/reference/plugin_list.rst b/doc/en/reference/plugin_list.rst index 50206c3415..ecd96b8996 100644 --- a/doc/en/reference/plugin_list.rst +++ b/doc/en/reference/plugin_list.rst @@ -27,15 +27,15 @@ please refer to `the update script =8.3 - :pypi:`logassert` Simple but powerful assertion and verification of logged lines. May 20, 2022 5 - Production/Stable N/A + :pypi:`databricks-labs-pytester` Python Testing for Databricks Nov 04, 2024 4 - Beta pytest>=8.3 + :pypi:`logassert` Simple but powerful assertion and verification of logged lines. Nov 08, 2024 5 - Production/Stable N/A :pypi:`logot` Test whether your code is logging correctly 🪵 Mar 23, 2024 5 - Production/Stable pytest<9,>=7; extra == "pytest" :pypi:`nuts` Network Unit Testing System Jul 19, 2024 N/A pytest<8,>=7 :pypi:`pytest-abq` Pytest integration for the ABQ universal test runner. Apr 07, 2023 N/A N/A @@ -157,7 +157,7 @@ This list contains 1538 plugins. :pypi:`pytest-bdd-wrappers` Feb 11, 2020 2 - Pre-Alpha N/A :pypi:`pytest-beakerlib` A pytest plugin that reports test results to the BeakerLib framework Mar 17, 2017 5 - Production/Stable pytest :pypi:`pytest-beartype` Pytest plugin to run your tests with beartype checking enabled. Oct 31, 2024 N/A pytest - :pypi:`pytest-bec-e2e` BEC pytest plugin for end-to-end tests Oct 22, 2024 3 - Alpha pytest + :pypi:`pytest-bec-e2e` BEC pytest plugin for end-to-end tests Nov 05, 2024 3 - Alpha pytest :pypi:`pytest-beds` Fixtures for testing Google Appengine (GAE) apps Jun 07, 2016 4 - Beta N/A :pypi:`pytest-beeprint` use icdiff for better error messages in pytest assertions Jul 04, 2023 4 - Beta N/A :pypi:`pytest-bench` Benchmark utility that plugs into pytest. Jul 21, 2014 3 - Alpha N/A @@ -246,7 +246,7 @@ This list contains 1538 plugins. :pypi:`pytest-cldf` Easy quality control for CLDF datasets using pytest Nov 07, 2022 N/A pytest (>=3.6) :pypi:`pytest-cleanslate` Collects and executes pytest tests separately Sep 04, 2024 N/A pytest :pypi:`pytest_cleanup` Automated, comprehensive and well-organised pytest test cases. Jan 28, 2020 N/A N/A - :pypi:`pytest-cleanuptotal` A cleanup plugin for pytest Sep 14, 2024 5 - Production/Stable N/A + :pypi:`pytest-cleanuptotal` A cleanup plugin for pytest Nov 08, 2024 5 - Production/Stable N/A :pypi:`pytest-clerk` A set of pytest fixtures to help with integration testing with Clerk. Oct 08, 2024 N/A pytest<9.0.0,>=8.0.0 :pypi:`pytest-click` Pytest plugin for Click Feb 11, 2022 5 - Production/Stable pytest (>=5.0) :pypi:`pytest-cli-fixtures` Automatically register fixtures for custom CLI arguments Jul 28, 2022 N/A pytest (~=7.0) @@ -571,7 +571,7 @@ This list contains 1538 plugins. :pypi:`pytest-fixtures` Common fixtures for pytest May 01, 2019 5 - Production/Stable N/A :pypi:`pytest-fixture-tools` Plugin for pytest which provides tools for fixtures Aug 15, 2024 6 - Mature pytest :pypi:`pytest-fixture-typecheck` A pytest plugin to assert type annotations at runtime. Aug 24, 2021 N/A pytest - :pypi:`pytest-flake8` pytest plugin to check FLAKE8 requirements Jul 21, 2024 5 - Production/Stable pytest>=7.0 + :pypi:`pytest-flake8` pytest plugin to check FLAKE8 requirements Nov 09, 2024 5 - Production/Stable pytest>=7.0 :pypi:`pytest-flake8-path` A pytest fixture for testing flake8 plugins. Oct 25, 2024 5 - Production/Stable pytest :pypi:`pytest-flake8-v2` pytest plugin to check FLAKE8 requirements Mar 01, 2022 5 - Production/Stable pytest (>=7.0) :pypi:`pytest-flakefinder` Runs tests multiple times to expose flakiness. Oct 26, 2022 4 - Beta pytest (>=2.7.1) @@ -601,7 +601,7 @@ This list contains 1538 plugins. :pypi:`pytest-frozen-uuids` Deterministically frozen UUID's for your tests Apr 17, 2022 N/A pytest (>=3.0) :pypi:`pytest-func-cov` Pytest plugin for measuring function coverage Apr 15, 2021 3 - Alpha pytest (>=5) :pypi:`pytest-funparam` An alternative way to parametrize test cases. Dec 02, 2021 4 - Beta pytest >=4.6.0 - :pypi:`pytest-fv` pytest extensions to support running functional-verification jobs Oct 11, 2024 N/A pytest + :pypi:`pytest-fv` pytest extensions to support running functional-verification jobs Nov 07, 2024 N/A pytest :pypi:`pytest-fxa` pytest plugin for Firefox Accounts Aug 28, 2018 5 - Production/Stable N/A :pypi:`pytest-fxa-mte` pytest plugin for Firefox Accounts Oct 02, 2024 5 - Production/Stable N/A :pypi:`pytest-fxtest` Oct 27, 2020 N/A N/A @@ -616,7 +616,7 @@ This list contains 1538 plugins. :pypi:`pytest-gherkin` A flexible framework for executing BDD gherkin tests Jul 27, 2019 3 - Alpha pytest (>=5.0.0) :pypi:`pytest-gh-log-group` pytest plugin for gh actions Jan 11, 2022 3 - Alpha pytest :pypi:`pytest-ghostinspector` For finding/executing Ghost Inspector tests May 17, 2016 3 - Alpha N/A - :pypi:`pytest-girder` A set of pytest fixtures for testing Girder applications. Jul 08, 2024 N/A pytest>=3.6 + :pypi:`pytest-girder` A set of pytest fixtures for testing Girder applications. Nov 07, 2024 N/A pytest>=3.6 :pypi:`pytest-git` Git repository fixture for py.test Oct 17, 2024 5 - Production/Stable pytest :pypi:`pytest-gitconfig` Provide a Git config sandbox for testing Aug 11, 2024 4 - Beta pytest>=7.1.2 :pypi:`pytest-gitcov` Pytest plugin for reporting on coverage of the last git commit. Jan 11, 2020 2 - Pre-Alpha N/A @@ -660,7 +660,7 @@ This list contains 1538 plugins. :pypi:`pytest-history` Pytest plugin to keep a history of your pytest runs Jan 14, 2024 N/A pytest (>=7.4.3,<8.0.0) :pypi:`pytest-home` Home directory fixtures Jul 28, 2024 5 - Production/Stable pytest :pypi:`pytest-homeassistant` A pytest plugin for use with homeassistant custom components. Aug 12, 2020 4 - Beta N/A - :pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Nov 01, 2024 3 - Alpha pytest==8.3.3 + :pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Nov 09, 2024 3 - Alpha pytest==8.3.3 :pypi:`pytest-honey` A simple plugin to use with pytest Jan 07, 2022 4 - Beta pytest (>=3.5.0) :pypi:`pytest-honors` Report on tests that honor constraints, and guard against regressions Mar 06, 2020 4 - Beta N/A :pypi:`pytest-hot-reloading` Sep 23, 2024 N/A N/A @@ -730,6 +730,7 @@ This list contains 1538 plugins. :pypi:`pytest-interface-tester` Pytest plugin for checking charm relation interface protocol compliance. Sep 25, 2024 4 - Beta pytest :pypi:`pytest-invenio` Pytest fixtures for Invenio. Jun 27, 2024 5 - Production/Stable pytest<7.2.0,>=6 :pypi:`pytest-involve` Run tests covering a specific file or changeset Feb 02, 2020 4 - Beta pytest (>=3.5.0) + :pypi:`pytest-iovis` A Pytest plugin to enable Jupyter Notebook testing with Papermill Nov 06, 2024 4 - Beta pytest>=7.1.0 :pypi:`pytest-ipdb` A py.test plug-in to enable drop to ipdb debugger on test failure. Mar 20, 2013 2 - Pre-Alpha N/A :pypi:`pytest-ipynb` THIS PROJECT IS ABANDONED Jan 29, 2019 3 - Alpha N/A :pypi:`pytest-ipywidgets` Oct 28, 2024 N/A pytest @@ -818,7 +819,7 @@ This list contains 1538 plugins. :pypi:`pytest-logger` Plugin configuring handlers for loggers from Python logging module. Mar 10, 2024 5 - Production/Stable pytest (>=3.2) :pypi:`pytest-logging` Configures logging and allows tweaking the log level with a py.test flag Nov 04, 2015 4 - Beta N/A :pypi:`pytest-logging-end-to-end-test-tool` Sep 23, 2022 N/A pytest (>=7.1.2,<8.0.0) - :pypi:`pytest-logikal` Common testing environment Oct 28, 2024 5 - Production/Stable pytest==8.3.3 + :pypi:`pytest-logikal` Common testing environment Nov 09, 2024 5 - Production/Stable pytest==8.3.3 :pypi:`pytest-log-report` Package for creating a pytest test run reprot Dec 26, 2019 N/A N/A :pypi:`pytest-logscanner` Pytest plugin for logscanner (A logger for python logging outputting to easily viewable (and filterable) html files. Good for people not grep savey, and color higlighting and quickly changing filters might even bye useful for commandline wizards.) Sep 30, 2024 4 - Beta pytest>=8.2.2 :pypi:`pytest-loguru` Pytest Loguru Mar 20, 2024 5 - Production/Stable pytest; extra == "test" @@ -859,7 +860,7 @@ This list contains 1538 plugins. :pypi:`pytest-messenger` Pytest to Slack reporting plugin Nov 24, 2022 5 - Production/Stable N/A :pypi:`pytest-metadata` pytest plugin for test session metadata Feb 12, 2024 5 - Production/Stable pytest>=7.0.0 :pypi:`pytest-metrics` Custom metrics report for pytest Apr 04, 2020 N/A pytest - :pypi:`pytest-mh` Pytest multihost plugin Sep 19, 2024 N/A pytest + :pypi:`pytest-mh` Pytest multihost plugin Nov 04, 2024 N/A pytest :pypi:`pytest-mimesis` Mimesis integration with the pytest test runner Mar 21, 2020 5 - Production/Stable pytest (>=4.2) :pypi:`pytest-minecraft` A pytest plugin for running tests against Minecraft releases Apr 06, 2022 N/A pytest (>=6.0.1) :pypi:`pytest-mini` A plugin to test mp Feb 06, 2023 N/A pytest (>=7.2.0,<8.0.0) @@ -1006,7 +1007,7 @@ This list contains 1538 plugins. :pypi:`pytest-pg` A tiny plugin for pytest which runs PostgreSQL in Docker May 21, 2024 5 - Production/Stable pytest>=6.0.0 :pypi:`pytest-pgsql` Pytest plugins and helpers for tests using a Postgres database. May 13, 2020 5 - Production/Stable pytest (>=3.0.0) :pypi:`pytest-phmdoctest` pytest plugin to test Python examples in Markdown using phmdoctest. Apr 15, 2022 4 - Beta pytest (>=5.4.3) - :pypi:`pytest-picked` Run the tests related to the changed files Jul 27, 2023 N/A pytest (>=3.7.0) + :pypi:`pytest-picked` Run the tests related to the changed files Nov 06, 2024 N/A pytest>=3.7.0 :pypi:`pytest-pigeonhole` Jun 25, 2018 5 - Production/Stable pytest (>=3.4) :pypi:`pytest-pikachu` Show surprise when tests are passing Aug 05, 2021 5 - Production/Stable pytest :pypi:`pytest-pilot` Slice in your test base thanks to powerful markers. Oct 09, 2020 5 - Production/Stable N/A @@ -1224,7 +1225,7 @@ This list contains 1538 plugins. :pypi:`pytest-sanity` Dec 07, 2020 N/A N/A :pypi:`pytest-sa-pg` May 14, 2019 N/A N/A :pypi:`pytest_sauce` pytest_sauce provides sane and helpful methods worked out in clearcode to run py.test tests with selenium/saucelabs Jul 14, 2014 3 - Alpha N/A - :pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Nov 01, 2024 5 - Production/Stable N/A + :pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Nov 09, 2024 5 - Production/Stable N/A :pypi:`pytest-scenario` pytest plugin for test scenarios Feb 06, 2017 3 - Alpha N/A :pypi:`pytest-scenario-files` A pytest plugin that generates unit test scenarios from data files. May 19, 2024 5 - Production/Stable pytest>=7.2.0 :pypi:`pytest-schedule` Automate and customize test scheduling effortlessly on local machines. Oct 31, 2024 N/A N/A @@ -1235,7 +1236,7 @@ This list contains 1538 plugins. :pypi:`pytest-select` A pytest plugin which allows to (de-)select tests from a file. Jan 18, 2019 3 - Alpha pytest (>=3.0) :pypi:`pytest-selenium` pytest plugin for Selenium Feb 01, 2024 5 - Production/Stable pytest>=6.0.0 :pypi:`pytest-selenium-auto` pytest plugin to automatically capture screenshots upon selenium webdriver events Nov 07, 2023 N/A pytest >= 7.0.0 - :pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Nov 01, 2024 5 - Production/Stable N/A + :pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Nov 09, 2024 5 - Production/Stable N/A :pypi:`pytest-selenium-enhancer` pytest plugin for Selenium Apr 29, 2022 5 - Production/Stable N/A :pypi:`pytest-selenium-pdiff` A pytest package implementing perceptualdiff for Selenium tests. Apr 06, 2017 2 - Pre-Alpha N/A :pypi:`pytest-selfie` A pytest plugin for selfie snapshot testing. Apr 05, 2024 N/A pytest<9.0.0,>=8.0.0 @@ -1281,6 +1282,7 @@ This list contains 1538 plugins. :pypi:`pytest-smartcollect` A plugin for collecting tests that touch changed code Oct 04, 2018 N/A pytest (>=3.5.0) :pypi:`pytest-smartcov` Smart coverage plugin for pytest. Sep 30, 2017 3 - Alpha N/A :pypi:`pytest-smell` Automated bad smell detection tool for Pytest Jun 26, 2022 N/A N/A + :pypi:`pytest-smoke` pytest plugin for supporting smoke testing Nov 07, 2024 4 - Beta pytest<9,>=7.0.0 :pypi:`pytest-smtp` Send email with pytest execution result Feb 20, 2021 N/A pytest :pypi:`pytest-smtp4dev` Plugin for smtp4dev API Jun 27, 2023 5 - Production/Stable N/A :pypi:`pytest-smtpd` An SMTP server for testing built on aiosmtpd May 15, 2023 N/A pytest @@ -1358,7 +1360,7 @@ This list contains 1538 plugins. :pypi:`pytest-symbols` pytest-symbols is a pytest plugin that adds support for passing test environment symbols into pytest tests. Nov 20, 2017 3 - Alpha N/A :pypi:`pytest-system-statistics` Pytest plugin to track and report system usage statistics Feb 16, 2022 5 - Production/Stable pytest (>=6.0.0) :pypi:`pytest-system-test-plugin` Pyst - Pytest System-Test Plugin Feb 03, 2022 N/A N/A - :pypi:`pytest_tagging` a pytest plugin to tag tests Aug 31, 2024 N/A pytest<8.0.0,>=7.1.3 + :pypi:`pytest_tagging` a pytest plugin to tag tests Nov 08, 2024 N/A pytest>=7.1.3 :pypi:`pytest-takeltest` Fixtures for ansible, testinfra and molecule Sep 07, 2024 N/A N/A :pypi:`pytest-talisker` Nov 28, 2021 N/A N/A :pypi:`pytest-tally` A Pytest plugin to generate realtime summary stats, and display them in-console using a text-based dashboard. May 22, 2023 4 - Beta pytest (>=6.2.5) @@ -1578,14 +1580,14 @@ This list contains 1538 plugins. :pypi:`databricks-labs-pytester` - *last release*: Oct 11, 2024, + *last release*: Nov 04, 2024, *status*: 4 - Beta, *requires*: pytest>=8.3 Python Testing for Databricks :pypi:`logassert` - *last release*: May 20, 2022, + *last release*: Nov 08, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -2439,7 +2441,7 @@ This list contains 1538 plugins. Pytest plugin to run your tests with beartype checking enabled. :pypi:`pytest-bec-e2e` - *last release*: Oct 22, 2024, + *last release*: Nov 05, 2024, *status*: 3 - Alpha, *requires*: pytest @@ -3062,7 +3064,7 @@ This list contains 1538 plugins. Automated, comprehensive and well-organised pytest test cases. :pypi:`pytest-cleanuptotal` - *last release*: Sep 14, 2024, + *last release*: Nov 08, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -5337,7 +5339,7 @@ This list contains 1538 plugins. A pytest plugin to assert type annotations at runtime. :pypi:`pytest-flake8` - *last release*: Jul 21, 2024, + *last release*: Nov 09, 2024, *status*: 5 - Production/Stable, *requires*: pytest>=7.0 @@ -5547,7 +5549,7 @@ This list contains 1538 plugins. An alternative way to parametrize test cases. :pypi:`pytest-fv` - *last release*: Oct 11, 2024, + *last release*: Nov 07, 2024, *status*: N/A, *requires*: pytest @@ -5652,7 +5654,7 @@ This list contains 1538 plugins. For finding/executing Ghost Inspector tests :pypi:`pytest-girder` - *last release*: Jul 08, 2024, + *last release*: Nov 07, 2024, *status*: N/A, *requires*: pytest>=3.6 @@ -5960,7 +5962,7 @@ This list contains 1538 plugins. A pytest plugin for use with homeassistant custom components. :pypi:`pytest-homeassistant-custom-component` - *last release*: Nov 01, 2024, + *last release*: Nov 09, 2024, *status*: 3 - Alpha, *requires*: pytest==8.3.3 @@ -6449,6 +6451,13 @@ This list contains 1538 plugins. Run tests covering a specific file or changeset + :pypi:`pytest-iovis` + *last release*: Nov 06, 2024, + *status*: 4 - Beta, + *requires*: pytest>=7.1.0 + + A Pytest plugin to enable Jupyter Notebook testing with Papermill + :pypi:`pytest-ipdb` *last release*: Mar 20, 2013, *status*: 2 - Pre-Alpha, @@ -7066,7 +7075,7 @@ This list contains 1538 plugins. :pypi:`pytest-logikal` - *last release*: Oct 28, 2024, + *last release*: Nov 09, 2024, *status*: 5 - Production/Stable, *requires*: pytest==8.3.3 @@ -7353,7 +7362,7 @@ This list contains 1538 plugins. Custom metrics report for pytest :pypi:`pytest-mh` - *last release*: Sep 19, 2024, + *last release*: Nov 04, 2024, *status*: N/A, *requires*: pytest @@ -8382,9 +8391,9 @@ This list contains 1538 plugins. pytest plugin to test Python examples in Markdown using phmdoctest. :pypi:`pytest-picked` - *last release*: Jul 27, 2023, + *last release*: Nov 06, 2024, *status*: N/A, - *requires*: pytest (>=3.7.0) + *requires*: pytest>=3.7.0 Run the tests related to the changed files @@ -9908,7 +9917,7 @@ This list contains 1538 plugins. pytest_sauce provides sane and helpful methods worked out in clearcode to run py.test tests with selenium/saucelabs :pypi:`pytest-sbase` - *last release*: Nov 01, 2024, + *last release*: Nov 09, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -9985,7 +9994,7 @@ This list contains 1538 plugins. pytest plugin to automatically capture screenshots upon selenium webdriver events :pypi:`pytest-seleniumbase` - *last release*: Nov 01, 2024, + *last release*: Nov 09, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -10306,6 +10315,13 @@ This list contains 1538 plugins. Automated bad smell detection tool for Pytest + :pypi:`pytest-smoke` + *last release*: Nov 07, 2024, + *status*: 4 - Beta, + *requires*: pytest<9,>=7.0.0 + + pytest plugin for supporting smoke testing + :pypi:`pytest-smtp` *last release*: Feb 20, 2021, *status*: N/A, @@ -10846,9 +10862,9 @@ This list contains 1538 plugins. Pyst - Pytest System-Test Plugin :pypi:`pytest_tagging` - *last release*: Aug 31, 2024, + *last release*: Nov 08, 2024, *status*: N/A, - *requires*: pytest<8.0.0,>=7.1.3 + *requires*: pytest>=7.1.3 a pytest plugin to tag tests From 70639efe8d33cdbf2590742b70da59efe09c977f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 07:39:17 +0100 Subject: [PATCH 11/18] build(deps): Bump django in /testing/plugins_integration (#12951) Bumps [django](https://github.com/django/django) from 5.1.2 to 5.1.3. - [Commits](https://github.com/django/django/compare/5.1.2...5.1.3) --- updated-dependencies: - dependency-name: django dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- testing/plugins_integration/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/plugins_integration/requirements.txt b/testing/plugins_integration/requirements.txt index ef01747f2f..32992dc258 100644 --- a/testing/plugins_integration/requirements.txt +++ b/testing/plugins_integration/requirements.txt @@ -1,5 +1,5 @@ anyio[curio,trio]==4.6.2.post1 -django==5.1.2 +django==5.1.3 pytest-asyncio==0.24.0 pytest-bdd==7.3.0 pytest-cov==6.0.0 From 7256c0c226b0eea2453cc532e6786366aa2400c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 08:39:14 +0100 Subject: [PATCH 12/18] build(deps): Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.12.2 (#12953) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.10.3 to 1.12.2. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.10.3...v1.12.2) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 974fe4947d..3d3cb7534a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -54,7 +54,7 @@ jobs: path: dist - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@v1.10.3 + uses: pypa/gh-action-pypi-publish@v1.12.2 with: attestations: true From c98ef2bdcaf4f0478c77c38534bce788e6581967 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 11 Nov 2024 15:09:18 +0100 Subject: [PATCH 13/18] change implementation so the check happens in pytest_fixture_setup after any hooks (from async plugins) has had a chance to resolve the awaitable --- src/_pytest/compat.py | 1 + src/_pytest/fixtures.py | 57 ++++++++++++++------------------------ testing/acceptance_test.py | 40 +++++++++++++------------- 3 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 614848e0db..6424013531 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -44,6 +44,7 @@ class NotSetType(enum.Enum): def is_generator(func: object) -> bool: + # note: this also returns true for async generator functions genfunc = inspect.isgeneratorfunction(func) return genfunc and not iscoroutinefunction(func) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 4b45489cd9..0737773f04 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -595,42 +595,6 @@ def _get_active_fixturedef( raise FixtureLookupError(argname, self) fixturedef = fixturedefs[index] - # Check for attempted use of an async fixture by a sync test - # `self.scope` here is not the scope of the requested fixture, but the scope of - # the requester. - if ( - self.scope == "function" - and not inspect.iscoroutinefunction(self._pyfuncitem.obj) - and ( - inspect.iscoroutinefunction(fixturedef.func) - or inspect.isasyncgenfunction(fixturedef.func) - ) - ): - if fixturedef._autouse: - warnings.warn( - PytestRemovedIn9Warning( - f"Sync test {self._pyfuncitem.name!r} requested async fixture " - f"{argname!r} with autouse=True. " - "If you intended to use the fixture you may want to make the " - "test asynchronous or the fixture synchronous. " - "If you did not intend to use it you should " - "restructure your test setup. " - "This will turn into an error in pytest 9." - ), - stacklevel=3, - ) - else: - warnings.warn( - PytestRemovedIn9Warning( - f"Sync test {self._pyfuncitem.name!r} requested async fixture " - f"{argname!r}. " - "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin, or make the fixture synchronous. " - "This will turn into an error in pytest 9." - ), - stacklevel=3, - ) - # Prepare a SubRequest object for calling the fixture. try: callspec = self._pyfuncitem.callspec @@ -921,6 +885,8 @@ def call_fixture_func( fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs ) -> FixtureValue: if is_generator(fixturefunc): + # note: this also triggers on async generators, suppressing 'unawaited coroutine' + # warning. fixturefunc = cast( Callable[..., Generator[FixtureValue, None, None]], fixturefunc ) @@ -1179,6 +1145,25 @@ def pytest_fixture_setup( fixturefunc = resolve_fixture_function(fixturedef, request) my_cache_key = fixturedef.cache_key(request) + + if inspect.isasyncgenfunction(fixturefunc) or inspect.iscoroutinefunction( + fixturefunc + ): + auto_str = " with autouse=True" if fixturedef._autouse else "" + + warnings.warn( + PytestRemovedIn9Warning( + f"{request.node.name!r} requested an async fixture " + f"{request.fixturename!r}{auto_str}, with no plugin or hook that " + "handled it. This is usually an error, as pytest does not natively " + "support it. If this is intentional, consider making the fixture " + "sync and return a coroutine/asyncgen. " + "This will turn into an error in pytest 9." + ), + # no stacklevel will point at users code, so we just point here + stacklevel=1, + ) + try: result = call_fixture_func(fixturefunc, request, kwargs) except TEST_OUTCOME as e: diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index a7a9afedbc..ffea0dbf46 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1306,11 +1306,13 @@ def test_foo(async_fixture): result = pytester.runpytest() result.stdout.fnmatch_lines( [ + "*== warnings summary ==*", ( - "*Sync test 'test_foo' requested async fixture " - "'async_fixture'. " - "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin, or make the fixture synchronous. " + "*PytestRemovedIn9Warning: 'test_foo' requested an async " + "fixture 'async_fixture', with no plugin or hook that handled it. " + "This is usually an error, as pytest does not natively support it. " + "If this is intentional, consider making the fixture sync and return " + "a coroutine/asyncgen. " "This will turn into an error in pytest 9." ), ] @@ -1328,21 +1330,21 @@ async def async_fixture(): yield def test_foo(async_fixture): - # suppress unawaited coroutine warning - try: - async_fixture.asend(None) - except StopIteration: - pass + # we don't need to suppress RuntimeWarning for unawaited coroutine + # as pytest internals accidentally do so already for async gens + ... """ ) result = pytester.runpytest() result.stdout.fnmatch_lines( [ + "*== warnings summary ==*", ( - "*Sync test 'test_foo' requested async fixture " - "'async_fixture'. " - "You may want to make the test asynchronous and run it with " - "a suitable async framework test plugin, or make the fixture synchronous. " + "*PytestRemovedIn9Warning: 'test_foo' requested an async " + "fixture 'async_fixture', with no plugin or hook that handled it. " + "This is usually an error, as pytest does not natively support it. " + "If this is intentional, consider making the fixture sync and return " + "a coroutine/asyncgen. " "This will turn into an error in pytest 9." ), ] @@ -1371,13 +1373,13 @@ def test_foo(async_fixture): result = pytester.runpytest() result.stdout.fnmatch_lines( [ + "*== warnings summary ==*", ( - "*Sync test 'test_foo' requested async fixture " - "'async_fixture' with autouse=True. " - "If you intended to use the fixture you may want to make the " - "test asynchronous or the fixture synchronous. " - "If you did not intend to use it you should " - "restructure your test setup. " + "*PytestRemovedIn9Warning: Sync test 'test_foo' requested an async " + "fixture 'async_fixture' with autouse=True, with no plugin or hook " + "that handled it. This is usually an error, as pytest does not " + "natively support it. If this is intentional, consider making the " + "fixture sync and return a coroutine/asyncgen. " "This will turn into an error in pytest 9." ), ] From cd3eb9800b8f36c257cfe4deb40ea275bb72e4e9 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 11 Nov 2024 15:20:25 +0100 Subject: [PATCH 14/18] fix test --- testing/acceptance_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index ffea0dbf46..ca6df943af 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1375,7 +1375,7 @@ def test_foo(async_fixture): [ "*== warnings summary ==*", ( - "*PytestRemovedIn9Warning: Sync test 'test_foo' requested an async " + "*PytestRemovedIn9Warning: 'test_foo' requested an async " "fixture 'async_fixture' with autouse=True, with no plugin or hook " "that handled it. This is usually an error, as pytest does not " "natively support it. If this is intentional, consider making the " From 876cc2a2b184bb68b0398ce7f9b7bbb3a731e787 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 11 Nov 2024 15:37:22 +0100 Subject: [PATCH 15/18] update docs/changelog --- changelog/10839.deprecation.rst | 2 +- doc/en/deprecations.rst | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog/10839.deprecation.rst b/changelog/10839.deprecation.rst index 78ad4e118e..01464ca0ba 100644 --- a/changelog/10839.deprecation.rst +++ b/changelog/10839.deprecation.rst @@ -1 +1 @@ -Synchronous tests that request an asynchronous fixture will now give a DeprecationWarning. This will introduce warnings in several pytest plugins that handle async tests/fixtures and for some users with custom setups. For guidance on how to manage this see :ref:`sync-test-async-fixture`. +Requesting an asynchronous fixture without a `pytest_fixture_setup` to handle it will now give a DeprecationWarning. This most commonly happens if a sync test requests an async fixture. This should have no effect on a majority of users with async tests or fixtures, but may affect non-standard hook setups or ``autouse=True``. For guidance on how to work around this warning see :ref:`sync-test-async-fixture`. diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index b384f01dfa..494bd88d28 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -24,13 +24,14 @@ sync test depending on async fixture Pytest has for a long time given an error when encountering an asynchronous test function, prompting the user to install a plugin that can handle it. It has not given any errors if you have an asynchronous fixture that's depended on by a -synchronous test. This is a problem even if you do have a plugin installed for handling async tests, as they may require +synchronous test. If the fixture was an async function you did get an "unawaited coroutine" warning, but for async yield fixtures you didn't even get that. +This is a problem even if you do have a plugin installed for handling async tests, as they may require special decorators for async fixtures to be handled, and some may not robustly handle if a user accidentally requests an async fixture from their sync tests. Fixture values being cached can make this even more unintuitive, where everything will "work" if the fixture is first requested by an async test, and then requested by a synchronous test. Unfortunately there is no 100% reliable method of identifying when a user has made a mistake, versus when they expect an -unawaited object from their fixture that they will handle - either on their own, or by a plugin. To suppress this warning +unawaited object from their fixture that they will handle on their own. To suppress this warning when you in fact did intend to handle this you can wrap your async fixture in a synchronous fixture: .. code-block:: python @@ -67,7 +68,10 @@ should be changed to def test_foo(unawaited_fixture): assert 1 == asyncio.run(unawaited_fixture) -If a user has an async fixture with ``autouse=True`` in their ``conftest.py``, or in a file where they also have synchronous tests, they will also get this warning. We strongly recommend against this practice, and they should restructure their testing infrastructure so the fixture is synchronous or to separate the fixture from their synchronous tests. Plugins that handle async may want to introduce helpers to make that easier in scenarios where that might be wanted, e.g. if setting up a database in an asynchronous way, or the user may opt to make their test async even though it might not strictly need to be. + +You can also make use of `pytest_fixture_setup` to handle the coroutine/asyncgen before pytest sees it - this is the way current async pytest plugins handle it. + +If a user has an async fixture with ``autouse=True`` in their ``conftest.py``, or in a file where they also have synchronous tests, they will also get this warning. We strongly recommend against this practice, and they should restructure their testing infrastructure so the fixture is synchronous or to separate the fixture from their synchronous tests. Note that the anyio pytest plugin has some support for sync test + async fixtures currently. .. _import-or-skip-import-error: From 1a4dfbb593fa63bbb3eeed2f79e730395f86b41a Mon Sep 17 00:00:00 2001 From: jakkdl Date: Thu, 14 Nov 2024 15:13:32 +0100 Subject: [PATCH 16/18] remove incorrect comments, add link --- doc/en/deprecations.rst | 2 +- src/_pytest/compat.py | 1 - src/_pytest/fixtures.py | 2 -- testing/acceptance_test.py | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index 494bd88d28..88cf3eccbf 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -71,7 +71,7 @@ should be changed to You can also make use of `pytest_fixture_setup` to handle the coroutine/asyncgen before pytest sees it - this is the way current async pytest plugins handle it. -If a user has an async fixture with ``autouse=True`` in their ``conftest.py``, or in a file where they also have synchronous tests, they will also get this warning. We strongly recommend against this practice, and they should restructure their testing infrastructure so the fixture is synchronous or to separate the fixture from their synchronous tests. Note that the anyio pytest plugin has some support for sync test + async fixtures currently. +If a user has an async fixture with ``autouse=True`` in their ``conftest.py``, or in a file where they also have synchronous tests, they will also get this warning. We strongly recommend against this practice, and they should restructure their testing infrastructure so the fixture is synchronous or to separate the fixture from their synchronous tests. Note that the `anyio pytest plugin `_ has some support for sync test + async fixtures currently. .. _import-or-skip-import-error: diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 6424013531..614848e0db 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -44,7 +44,6 @@ class NotSetType(enum.Enum): def is_generator(func: object) -> bool: - # note: this also returns true for async generator functions genfunc = inspect.isgeneratorfunction(func) return genfunc and not iscoroutinefunction(func) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 0737773f04..95e4557fc8 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -885,8 +885,6 @@ def call_fixture_func( fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs ) -> FixtureValue: if is_generator(fixturefunc): - # note: this also triggers on async generators, suppressing 'unawaited coroutine' - # warning. fixturefunc = cast( Callable[..., Generator[FixtureValue, None, None]], fixturefunc ) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index ca6df943af..624a313ca8 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1330,8 +1330,7 @@ async def async_fixture(): yield def test_foo(async_fixture): - # we don't need to suppress RuntimeWarning for unawaited coroutine - # as pytest internals accidentally do so already for async gens + # async gens don't emit unawaited-coroutine ... """ ) From d35e4ebad03a6f542304573b12e90848d2169c77 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Thu, 14 Nov 2024 15:16:28 +0100 Subject: [PATCH 17/18] revert now unrelated fix --- src/_pytest/fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 95e4557fc8..011dc8e6e3 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -807,7 +807,7 @@ def formatrepr(self) -> FixtureLookupErrorRepr: stack = [self.request._pyfuncitem.obj] stack.extend(map(lambda x: x.func, self.fixturestack)) msg = self.msg - if msg is not None and len(stack) > 1: + if msg is not None: # The last fixture raise an error, let's present # it at the requesting side. stack = stack[:-1] From ef096cda884d9f001916336e7e8c543badeb191f Mon Sep 17 00:00:00 2001 From: jakkdl Date: Thu, 14 Nov 2024 15:19:38 +0100 Subject: [PATCH 18/18] small wording changes --- changelog/10839.deprecation.rst | 2 +- src/_pytest/fixtures.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog/10839.deprecation.rst b/changelog/10839.deprecation.rst index 01464ca0ba..a3e2cbf51d 100644 --- a/changelog/10839.deprecation.rst +++ b/changelog/10839.deprecation.rst @@ -1 +1 @@ -Requesting an asynchronous fixture without a `pytest_fixture_setup` to handle it will now give a DeprecationWarning. This most commonly happens if a sync test requests an async fixture. This should have no effect on a majority of users with async tests or fixtures, but may affect non-standard hook setups or ``autouse=True``. For guidance on how to work around this warning see :ref:`sync-test-async-fixture`. +Requesting an asynchronous fixture without a `pytest_fixture_setup` hook that resolves it will now give a DeprecationWarning. This most commonly happens if a sync test requests an async fixture. This should have no effect on a majority of users with async tests or fixtures using async pytest plugins, but may affect non-standard hook setups or ``autouse=True``. For guidance on how to work around this warning see :ref:`sync-test-async-fixture`. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 011dc8e6e3..b5c64856e1 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -961,7 +961,7 @@ def __init__( ids: tuple[object | None, ...] | Callable[[Any], object | None] | None = None, *, _ispytest: bool = False, - # only used to emit a deprecationwarning, can be removed in pytest9 + # only used in a deprecationwarning msg, can be removed in pytest9 _autouse: bool = False, ) -> None: check_ispytest(_ispytest)