Skip to content

Commit 8248946

Browse files
Do not collect symlinked tests under Windows (#12050)
The check for short paths under Windows via os.path.samefile, introduced in #11936, also found similar tests in symlinked tests in the GH Actions CI. Fixes #12039. Co-authored-by: Bruno Oliveira <[email protected]>
1 parent 6ed0051 commit 8248946

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ Mike Hoyle (hoylemd)
283283
Mike Lundy
284284
Milan Lesnek
285285
Miro Hrončok
286+
mrbean-bremen
286287
Nathaniel Compton
287288
Nathaniel Waisbrot
288289
Ned Batchelder

changelog/12039.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a regression in ``8.0.2`` where tests created using :fixture:`tmp_path` have been collected multiple times in CI under Windows.

src/_pytest/main.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,14 @@ def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
924924
if sys.platform == "win32" and not is_match:
925925
# In case the file paths do not match, fallback to samefile() to
926926
# account for short-paths on Windows (#11895).
927-
is_match = os.path.samefile(node.path, matchparts[0])
927+
same_file = os.path.samefile(node.path, matchparts[0])
928+
# We don't want to match links to the current node,
929+
# otherwise we would match the same file more than once (#12039).
930+
is_match = same_file and (
931+
os.path.islink(node.path)
932+
== os.path.islink(matchparts[0])
933+
)
934+
928935
# Name part e.g. `TestIt` in `/a/b/test_file.py::TestIt::test_it`.
929936
else:
930937
# TODO: Remove parametrized workaround once collection structure contains

testing/test_collection.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -1765,7 +1765,7 @@ def test_foo(): assert True
17651765

17661766
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
17671767
def test_collect_short_file_windows(pytester: Pytester) -> None:
1768-
"""Reproducer for #11895: short paths not colleced on Windows."""
1768+
"""Reproducer for #11895: short paths not collected on Windows."""
17691769
short_path = tempfile.mkdtemp()
17701770
if "~" not in short_path: # pragma: no cover
17711771
if running_on_ci():
@@ -1832,3 +1832,28 @@ def test_pyargs_collection_tree(pytester: Pytester, monkeypatch: MonkeyPatch) ->
18321832
],
18331833
consecutive=True,
18341834
)
1835+
1836+
1837+
def test_do_not_collect_symlink_siblings(
1838+
pytester: Pytester, tmp_path: Path, request: pytest.FixtureRequest
1839+
) -> None:
1840+
"""
1841+
Regression test for #12039: Do not collect from directories that are symlinks to other directories in the same path.
1842+
1843+
The check for short paths under Windows via os.path.samefile, introduced in #11936, also finds the symlinked
1844+
directory created by tmp_path/tmpdir.
1845+
"""
1846+
# Use tmp_path because it creates a symlink with the name "current" next to the directory it creates.
1847+
symlink_path = tmp_path.parent / (tmp_path.name[:-1] + "current")
1848+
assert symlink_path.is_symlink() is True
1849+
1850+
# Create test file.
1851+
tmp_path.joinpath("test_foo.py").write_text("def test(): pass", encoding="UTF-8")
1852+
1853+
# Ensure we collect it only once if we pass the tmp_path.
1854+
result = pytester.runpytest(tmp_path, "-sv")
1855+
result.assert_outcomes(passed=1)
1856+
1857+
# Ensure we collect it only once if we pass the symlinked directory.
1858+
result = pytester.runpytest(symlink_path, "-sv")
1859+
result.assert_outcomes(passed=1)

0 commit comments

Comments
 (0)