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:
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user