From 23b91d12de9bcbd0ce965bebefcbcc53a588b438 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Thu, 8 Feb 2024 03:09:19 +0200 Subject: [PATCH] [8.0.x] Merge pull request #11941 from bluetech/doctest-parsefactories (#11948) doctest: fix autouse fixtures possibly not getting picked up (cherry picked from commit 6c0b6c2f92b68757988cdb11499cac750ba71862) --- changelog/11929.bugfix.rst | 1 + src/_pytest/doctest.py | 16 ++++++++-------- testing/test_doctest.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 changelog/11929.bugfix.rst diff --git a/changelog/11929.bugfix.rst b/changelog/11929.bugfix.rst new file mode 100644 index 00000000000..8ab50e6f451 --- /dev/null +++ b/changelog/11929.bugfix.rst @@ -0,0 +1 @@ +Fix a regression in pytest 8.0.0 whereby autouse fixtures defined in a module get ignored by the doctests in the module. diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index 61f13834c46..c6b1a9df5cc 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -40,7 +40,6 @@ from _pytest.outcomes import OutcomeException from _pytest.outcomes import skip from _pytest.pathlib import fnmatch_ex -from _pytest.pathlib import import_path from _pytest.python import Module from _pytest.python_api import approx from _pytest.warning_types import PytestWarning @@ -107,7 +106,7 @@ def pytest_addoption(parser: Parser) -> None: "--doctest-ignore-import-errors", action="store_true", default=False, - help="Ignore doctest ImportErrors", + help="Ignore doctest collection errors", dest="doctest_ignore_import_errors", ) group.addoption( @@ -568,16 +567,17 @@ def _from_module(self, module, object): ) else: try: - module = import_path( - self.path, - root=self.config.rootpath, - mode=self.config.getoption("importmode"), - ) - except ImportError: + module = self.obj + except Collector.CollectError: if self.config.getvalue("doctest_ignore_import_errors"): skip("unable to import module %r" % self.path) else: raise + + # While doctests currently don't support fixtures directly, we still + # need to pick up autouse fixtures. + self.session._fixturemanager.parsefactories(self) + # Uses internal doctest module parsing mechanism. finder = MockAwareDocTestFinder() optionflags = get_optionflags(self.config) diff --git a/testing/test_doctest.py b/testing/test_doctest.py index abe407eb8d2..e8a35fe9b98 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -1375,6 +1375,38 @@ def auto(request): str(result.stdout.no_fnmatch_line("*FAILURES*")) result.stdout.fnmatch_lines(["*=== 1 passed in *"]) + @pytest.mark.parametrize("scope", [*SCOPES, "package"]) + def test_auto_use_defined_in_same_module( + self, pytester: Pytester, scope: str + ) -> None: + """Autouse fixtures defined in the same module as the doctest get picked + up properly. + + Regression test for #11929. + """ + pytester.makepyfile( + f""" + import pytest + + AUTO = "the fixture did not run" + + @pytest.fixture(autouse=True, scope="{scope}") + def auto(request): + global AUTO + AUTO = "the fixture ran" + + def my_doctest(): + '''My doctest. + + >>> my_doctest() + 'the fixture ran' + ''' + return AUTO + """ + ) + result = pytester.runpytest("--doctest-modules") + result.assert_outcomes(passed=1) + class TestDoctestNamespaceFixture: SCOPES = ["module", "session", "class", "function"]