Merge branch 'main' into improve-high-scope-fixtures-teardown-issue-3806
This commit is contained in:
commit
6fc6b153fd
|
@ -0,0 +1 @@
|
|||
Fixed the ``--last-failed`` whole-file skipping functionality ("skipped N files") for :ref:`non-python test files <non-python tests>`.
|
|
@ -27,7 +27,7 @@ from _pytest.deprecated import check_ispytest
|
|||
from _pytest.fixtures import fixture
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.main import Session
|
||||
from _pytest.python import Module
|
||||
from _pytest.nodes import File
|
||||
from _pytest.python import Package
|
||||
from _pytest.reports import TestReport
|
||||
|
||||
|
@ -226,15 +226,23 @@ class LFPluginCollWrapper:
|
|||
# Sort any lf-paths to the beginning.
|
||||
lf_paths = self.lfplugin._last_failed_paths
|
||||
|
||||
# Use stable sort to priorize last failed.
|
||||
def sort_key(node: Union[nodes.Item, nodes.Collector]) -> bool:
|
||||
# Package.path is the __init__.py file, we need the directory.
|
||||
if isinstance(node, Package):
|
||||
path = node.path.parent
|
||||
else:
|
||||
path = node.path
|
||||
return path in lf_paths
|
||||
|
||||
res.result = sorted(
|
||||
res.result,
|
||||
# use stable sort to priorize last failed
|
||||
key=lambda x: x.path in lf_paths,
|
||||
key=sort_key,
|
||||
reverse=True,
|
||||
)
|
||||
return
|
||||
|
||||
elif isinstance(collector, Module):
|
||||
elif isinstance(collector, File):
|
||||
if collector.path in self.lfplugin._last_failed_paths:
|
||||
out = yield
|
||||
res = out.get_result()
|
||||
|
@ -272,10 +280,9 @@ class LFPluginCollSkipfiles:
|
|||
def pytest_make_collect_report(
|
||||
self, collector: nodes.Collector
|
||||
) -> Optional[CollectReport]:
|
||||
# Packages are Modules, but _last_failed_paths only contains
|
||||
# test-bearing paths and doesn't try to include the paths of their
|
||||
# packages, so don't filter them.
|
||||
if isinstance(collector, Module) and not isinstance(collector, Package):
|
||||
# Packages are Files, but we only want to skip test-bearing Files,
|
||||
# so don't filter Packages.
|
||||
if isinstance(collector, File) and not isinstance(collector, Package):
|
||||
if collector.path not in self.lfplugin._last_failed_paths:
|
||||
self.lfplugin._skipped_files += 1
|
||||
|
||||
|
@ -305,9 +312,14 @@ class LFPlugin:
|
|||
)
|
||||
|
||||
def get_last_failed_paths(self) -> Set[Path]:
|
||||
"""Return a set with all Paths()s of the previously failed nodeids."""
|
||||
"""Return a set with all Paths of the previously failed nodeids and
|
||||
their parents."""
|
||||
rootpath = self.config.rootpath
|
||||
result = {rootpath / nodeid.split("::")[0] for nodeid in self.lastfailed}
|
||||
result = set()
|
||||
for nodeid in self.lastfailed:
|
||||
path = rootpath / nodeid.split("::")[0]
|
||||
result.add(path)
|
||||
result.update(path.parents)
|
||||
return {x for x in result if x.exists()}
|
||||
|
||||
def pytest_report_collectionfinish(self) -> Optional[str]:
|
||||
|
|
|
@ -56,7 +56,6 @@ from _pytest.config import ExitCode
|
|||
from _pytest.config import hookimpl
|
||||
from _pytest.config.argparsing import Parser
|
||||
from _pytest.deprecated import check_ispytest
|
||||
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
|
||||
from _pytest.deprecated import INSTANCE_COLLECTOR
|
||||
from _pytest.deprecated import NOSE_SUPPORT_METHOD
|
||||
from _pytest.fixtures import FixtureDef
|
||||
|
@ -698,14 +697,6 @@ class Package(Module):
|
|||
func = partial(_call_with_optional_argument, teardown_module, self.obj)
|
||||
self.addfinalizer(func)
|
||||
|
||||
def gethookproxy(self, fspath: "os.PathLike[str]"):
|
||||
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
|
||||
return self.session.gethookproxy(fspath)
|
||||
|
||||
def isinitpath(self, path: Union[str, "os.PathLike[str]"]) -> bool:
|
||||
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
|
||||
return self.session.isinitpath(path)
|
||||
|
||||
def _recurse(self, direntry: "os.DirEntry[str]") -> bool:
|
||||
if direntry.name == "__pycache__":
|
||||
return False
|
||||
|
|
|
@ -105,7 +105,7 @@ def tw_mock():
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def dummy_yaml_custom_test(pytester: Pytester):
|
||||
def dummy_yaml_custom_test(pytester: Pytester) -> None:
|
||||
"""Writes a conftest file that collects and executes a dummy yaml test.
|
||||
|
||||
Taken from the docs, but stripped down to the bare minimum, useful for
|
||||
|
|
|
@ -854,6 +854,33 @@ class TestLastFailed:
|
|||
]
|
||||
)
|
||||
|
||||
def test_lastfailed_skip_collection_with_nesting(self, pytester: Pytester) -> None:
|
||||
"""Check that file skipping works even when the file with failures is
|
||||
nested at a different level of the collection tree."""
|
||||
pytester.makepyfile(
|
||||
**{
|
||||
"test_1.py": """
|
||||
def test_1(): pass
|
||||
""",
|
||||
"pkg/__init__.py": "",
|
||||
"pkg/test_2.py": """
|
||||
def test_2(): assert False
|
||||
""",
|
||||
}
|
||||
)
|
||||
# first run
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["collected 2 items", "*1 failed*1 passed*"])
|
||||
# second run - test_1.py is skipped.
|
||||
result = pytester.runpytest("--lf")
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"collected 1 item",
|
||||
"run-last-failure: rerun previous 1 failure (skipped 1 file)",
|
||||
"*= 1 failed in *",
|
||||
]
|
||||
)
|
||||
|
||||
def test_lastfailed_with_known_failures_not_being_selected(
|
||||
self, pytester: Pytester
|
||||
) -> None:
|
||||
|
@ -1058,6 +1085,28 @@ class TestLastFailed:
|
|||
result = pytester.runpytest("--lf")
|
||||
result.assert_outcomes(failed=3)
|
||||
|
||||
def test_non_python_file_skipped(
|
||||
self,
|
||||
pytester: Pytester,
|
||||
dummy_yaml_custom_test: None,
|
||||
) -> None:
|
||||
pytester.makepyfile(
|
||||
**{
|
||||
"test_bad.py": """def test_bad(): assert False""",
|
||||
},
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["collected 2 items", "* 1 failed, 1 passed in *"])
|
||||
|
||||
result = pytester.runpytest("--lf")
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"collected 1 item",
|
||||
"run-last-failure: rerun previous 1 failure (skipped 1 file)",
|
||||
"* 1 failed in *",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class TestNewFirst:
|
||||
def test_newfirst_usecase(self, pytester: Pytester) -> None:
|
||||
|
|
Loading…
Reference in New Issue