doctest: fix autouse fixtures possibly not getting picked up
Fix #11929. Figured out what's going on. We have the following collection tree: ``` <Dir pyspacewar> <Dir src> <Package pyspacewar> <Package tests> <DoctestModule test_main.py> <DoctestItem pyspacewar.tests.test_main.doctest_main> ``` And the `test_main.py` contains an autouse fixture (`fake_game_ui`) that `doctest_main` needs in order to run properly. The fixture doesn't run! It doesn't run because nothing collects the fixtures from (calls `parsefactories()` on) the `test_main.py` `DoctestModule`. How come it only started happening with commit ab63ebb3dc07b89670b96ae97044f48406c44fa0? Turns out it mostly only worked accidentally. Each `DoctestModule` is also collected as a normal `Module`, with the `Module` collected after the `DoctestModule`. For example, if we add a non-doctest test to `test_main.py`, the collection tree looks like this: ``` <Dir pyspacewar> <Dir src> <Package pyspacewar> <Package tests> <DoctestModule test_main.py> <DoctestItem pyspacewar.tests.test_main.doctest_main> <Module test_main.py> <Function test_it> ``` Now, `Module` *does* collect fixtures. When autouse fixtures are collected, they are added to the `_nodeid_autousenames` dict. Beforeab63ebb3dc
, `DoctestItem` consults `_nodeid_autousenames` at *setup* time. At this point, the `Module` has collected and so it ended up picking the autouse fixture (this relies on another "accident", that the `DoctestModule` and `Module` have the same node ID). Afterab63ebb3dc
, `DoctestItem` consults `_nodeid_autousenames` at *collection* time (= when it's created). At this point, the `Module` hasn't collected yet, so the autouse fixture is not picked out. The fix is simple -- have `DoctestModule.collect()` call `parsefactories`. From some testing I've done it shouldn't have negative consequences (I hope).
This commit is contained in:
parent
6e5008f19f
commit
9cd14b4ffb
|
@ -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.
|
|
@ -567,6 +567,10 @@ class DoctestModule(Module):
|
|||
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)
|
||||
|
|
|
@ -1376,6 +1376,38 @@ class TestDoctestAutoUseFixtures:
|
|||
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"]
|
||||
|
|
Loading…
Reference in New Issue