Skip to content

Commit 4b823a4

Browse files
authored
Merge pull request #11059 from bluetech/lf-skip-across
cacheprovider: fix file-skipping functionality across packages
2 parents 6c9b277 + c76ae74 commit 4b823a4

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

src/_pytest/cacheprovider.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,18 @@ def pytest_make_collect_report(self, collector: nodes.Collector):
226226
# Sort any lf-paths to the beginning.
227227
lf_paths = self.lfplugin._last_failed_paths
228228

229+
# Use stable sort to priorize last failed.
230+
def sort_key(node: Union[nodes.Item, nodes.Collector]) -> bool:
231+
# Package.path is the __init__.py file, we need the directory.
232+
if isinstance(node, Package):
233+
path = node.path.parent
234+
else:
235+
path = node.path
236+
return path in lf_paths
237+
229238
res.result = sorted(
230239
res.result,
231-
# use stable sort to priorize last failed
232-
key=lambda x: x.path in lf_paths,
240+
key=sort_key,
233241
reverse=True,
234242
)
235243
return
@@ -272,9 +280,8 @@ def __init__(self, lfplugin: "LFPlugin") -> None:
272280
def pytest_make_collect_report(
273281
self, collector: nodes.Collector
274282
) -> Optional[CollectReport]:
275-
# Packages are Modules, but _last_failed_paths only contains
276-
# test-bearing paths and doesn't try to include the paths of their
277-
# packages, so don't filter them.
283+
# Packages are Modules, but we only want to skip test-bearing Modules,
284+
# so don't filter Packages.
278285
if isinstance(collector, Module) and not isinstance(collector, Package):
279286
if collector.path not in self.lfplugin._last_failed_paths:
280287
self.lfplugin._skipped_files += 1
@@ -305,9 +312,14 @@ def __init__(self, config: Config) -> None:
305312
)
306313

307314
def get_last_failed_paths(self) -> Set[Path]:
308-
"""Return a set with all Paths()s of the previously failed nodeids."""
315+
"""Return a set with all Paths of the previously failed nodeids and
316+
their parents."""
309317
rootpath = self.config.rootpath
310-
result = {rootpath / nodeid.split("::")[0] for nodeid in self.lastfailed}
318+
result = set()
319+
for nodeid in self.lastfailed:
320+
path = rootpath / nodeid.split("::")[0]
321+
result.add(path)
322+
result.update(path.parents)
311323
return {x for x in result if x.exists()}
312324

313325
def pytest_report_collectionfinish(self) -> Optional[str]:

testing/test_cacheprovider.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,33 @@ def test_3(): pass
854854
]
855855
)
856856

857+
def test_lastfailed_skip_collection_with_nesting(self, pytester: Pytester) -> None:
858+
"""Check that file skipping works even when the file with failures is
859+
nested at a different level of the collection tree."""
860+
pytester.makepyfile(
861+
**{
862+
"test_1.py": """
863+
def test_1(): pass
864+
""",
865+
"pkg/__init__.py": "",
866+
"pkg/test_2.py": """
867+
def test_2(): assert False
868+
""",
869+
}
870+
)
871+
# first run
872+
result = pytester.runpytest()
873+
result.stdout.fnmatch_lines(["collected 2 items", "*1 failed*1 passed*"])
874+
# second run - test_1.py is skipped.
875+
result = pytester.runpytest("--lf")
876+
result.stdout.fnmatch_lines(
877+
[
878+
"collected 1 item",
879+
"run-last-failure: rerun previous 1 failure (skipped 1 file)",
880+
"*= 1 failed in *",
881+
]
882+
)
883+
857884
def test_lastfailed_with_known_failures_not_being_selected(
858885
self, pytester: Pytester
859886
) -> None:

0 commit comments

Comments
 (0)