Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/xdist/workermanage.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,16 @@ def make_reltoroot(roots: Sequence[Path], args: list[str]) -> list[str]:
result = []
for arg in args:
parts = arg.split(splitcode)
fspath = Path(parts[0])
# py.path.local (used here prior to migrating to pathlib)
# transparently resolved a relative path against the current
# working directory. Plain pathlib.Path does not do this, so
# a relative path given on the command line (e.g.
# "tests/test_sample.py") would never compare equal to, or as
# a subpath of, any of the (absolute) rsync roots below via
# relative_to() -- even when it does in fact point inside one
# of them once resolved against the cwd. Resolve it explicitly
# to restore the old behavior. See GH #971.
fspath = Path(parts[0]).resolve()
try:
exists = fspath.exists()
except OSError:
Expand Down
58 changes: 58 additions & 0 deletions testing/test_workermanage.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,3 +519,61 @@ def test_warning_serialization_tweaked_module() -> None:
# __module__ cannot be found!
with pytest.raises(ModuleNotFoundError):
unserialize_warning_message(data)


class TestMakeReltoroot:
"""Regression tests for GH#971.

A relative path given as a test-selection arg on the command line
(e.g. ``pytest tests/test_sample.py``, as opposed to an absolute
path) must still be correctly recognized as being inside one of
the rsync roots. ``py.path.local`` (used here prior to migrating
to ``pathlib``) transparently resolved a relative path against the
current working directory; plain ``pathlib.Path`` does not do
this on its own.
"""

def test_relative_arg_inside_root(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
root = tmp_path / "project"
(root / "tests").mkdir(parents=True)
test_file = root / "tests" / "test_sample.py"
test_file.write_text("def test_x(): pass\n")

monkeypatch.chdir(root)
result = workermanage.make_reltoroot([root], ["tests/test_sample.py"])
assert result == [f"{root.name}/tests/test_sample.py"]

def test_relative_arg_with_test_id_suffix(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
root = tmp_path / "project"
(root / "tests").mkdir(parents=True)
test_file = root / "tests" / "test_sample.py"
test_file.write_text("def test_x(): pass\n")

monkeypatch.chdir(root)
result = workermanage.make_reltoroot([root], ["tests/test_sample.py::test_x"])
assert result == [f"{root.name}/tests/test_sample.py::test_x"]

def test_absolute_arg_inside_root_still_works(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
root = tmp_path / "project"
(root / "tests").mkdir(parents=True)
test_file = root / "tests" / "test_sample.py"
test_file.write_text("def test_x(): pass\n")

monkeypatch.chdir(tmp_path) # cwd unrelated to the arg itself
result = workermanage.make_reltoroot([root], [str(test_file)])
assert result == [f"{root.name}/tests/test_sample.py"]

def test_nonexistent_relative_arg_passes_through_unchanged(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
root = tmp_path / "project"
root.mkdir()
monkeypatch.chdir(root)
result = workermanage.make_reltoroot([root], ["does/not/exist.py"])
assert result == ["does/not/exist.py"]
Loading