diff --git a/changelog/7814.bugfix.rst b/changelog/7814.bugfix.rst new file mode 100644 index 000000000..a5f2a9a95 --- /dev/null +++ b/changelog/7814.bugfix.rst @@ -0,0 +1 @@ +Fixed crash in header reporting when :confval:`testpaths` is used and contains absolute paths (regression in 6.1.0). diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py index 7179a786d..de8917be2 100644 --- a/src/_pytest/pathlib.py +++ b/src/_pytest/pathlib.py @@ -578,7 +578,10 @@ def absolutepath(path: Union[Path, str]) -> Path: def commonpath(path1: Path, path2: Path) -> Optional[Path]: """Return the common part shared with the other path, or None if there is - no common part.""" + no common part. + + If one path is relative and one is absolute, returns None. + """ try: return Path(os.path.commonpath((str(path1), str(path2)))) except ValueError: @@ -589,13 +592,17 @@ def bestrelpath(directory: Path, dest: Path) -> str: """Return a string which is a relative path from directory to dest such that directory/bestrelpath == dest. + The paths must be either both absolute or both relative. + If no such path can be determined, returns dest. """ if dest == directory: return os.curdir # Find the longest common directory. base = commonpath(directory, dest) - # Can be the case on Windows. + # Can be the case on Windows for two absolute paths on different drives. + # Can be the case for two relative paths without common prefix. + # Can be the case for a relative path and an absolute path. if not base: return str(dest) reldirectory = directory.relative_to(base) diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 727c15cb8..21634cbbc 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -718,10 +718,10 @@ class TerminalReporter: if config.inipath: line += ", configfile: " + bestrelpath(config.rootpath, config.inipath) - testpaths = config.getini("testpaths") - if testpaths and config.args == testpaths: - rel_paths = [bestrelpath(config.rootpath, x) for x in testpaths] - line += ", testpaths: {}".format(", ".join(rel_paths)) + testpaths = config.getini("testpaths") # type: List[str] + if config.invocation_params.dir == config.rootpath and config.args == testpaths: + line += ", testpaths: {}".format(", ".join(testpaths)) + result = [line] plugininfo = config.pluginmanager.list_plugin_distinfo() diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 859e1470e..9a2840631 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -18,6 +18,7 @@ import pytest from _pytest._io.wcwidth import wcswidth from _pytest.config import Config from _pytest.config import ExitCode +from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import Path from _pytest.pytester import Testdir from _pytest.reports import BaseReport @@ -749,6 +750,29 @@ class TestTerminalFunctional: result = testdir.runpytest("tests") result.stdout.fnmatch_lines(["rootdir: *test_header0, configfile: tox.ini"]) + def test_header_absolute_testpath( + self, testdir: Testdir, monkeypatch: MonkeyPatch + ) -> None: + """Regresstion test for #7814.""" + tests = testdir.tmpdir.join("tests") + tests.ensure_dir() + testdir.makepyprojecttoml( + """ + [tool.pytest.ini_options] + testpaths = ['{}'] + """.format( + tests + ) + ) + result = testdir.runpytest() + result.stdout.fnmatch_lines( + [ + "rootdir: *absolute_testpath0, configfile: pyproject.toml, testpaths: {}".format( + tests + ) + ] + ) + def test_no_header(self, testdir): testdir.tmpdir.join("tests").ensure_dir() testdir.tmpdir.join("gui").ensure_dir()