You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pytest 8.0.2 may collect tests multiple times under Windows #12039
I'm not quite sure if this is a bug, or a problem with the test or GitHub Actions, but since version 8.0.2 a test in pytest-order fails in the CI under Windows, which worked fine in 8.0.1 and previous versions. Linux and macOS tests are not affected.
The actual test should collect 6 items (3 tests per test module, in 2 modules) that are created in the directory provided by the tempdir fixture,
but collects 24 tests in the CI instead. Locally, it works as expected.
Checking the failed tests revealed that the tests have been collected from different locations. The tempdir had been at: C:\\Users\\runneradmin\\AppData\\Local\\Temp\\pytest-of-runneradmin\\pytest-9\\test_xdist_ordering0
(for a specific run), but the same tests have been discovered with a test ID with just the qualified test name, and additionally with the test IDs: ::::Users::runneradmin::AppData::Local::Temp::pytest-of-runneradmin::pytest-9:::xxx and ::::Documents and Settings::runneradmin::AppData::Local::Temp::pytest-of-runneradmin::pytest-9::xxx,
which are most likely aliases.
I haven't dug into this yet, but I suspect it may have something to do with the fix for the problem with short paths.
I can confirm that removing the fix for short paths (e.g. the line that uses os.path.samefile for the match) fixes the problem in the CI. Still no luck to reproduce this locally.
@nicoddemus: I think the test using samefile is too broad, as it also finds symlinks and junctions, which we don't wont.
I tested to adapt the check to filter out links and junctions to regular directories, which fixes the problem in the CI:
ifsys.platform=="win32"andnotis_match:
# In case the file paths do not match,# account for short-paths on Windows (#11895).same_file=os.path.samefile(node.path, matchparts[0])
# we don't want to find links or junctions, so we at least# exclude links/junctions to regular directoriesis_match= (
same_fileandos.path.islink(node.path) ==os.path.islink(matchparts[0]) and_is_junction(node.path) ==_is_junction(matchparts[0])
)
(is_junction is basically a copy of the Python 3.12 implementation of os.path.junction).
This does not not exclude links to other links to the same directory, but I would say that these are very unlikely cases.
Directly checking the short paths using ctypes and GetShortPath (which might be more correct) is possible, but ugly...
Just the islink check is enough to fix your CI? If so, I think we can easily just add this extra check. Junctions are more rare (I believe), so I think we can leave them out of this fix for now, as it requires extra steps (or we can just check for them in 3.12 at least).
I wouldn't say that junctions are rare (I use them all the time under Windows, as you need admin rights to create symlinks there), but maybe they are indeed rare for use cases with pytest. I will check tomorrow, if the check for links is sufficient for the CI.
Actually I wrote a test very similar to yours, and it passed locally, but failed in the CI (though with 2 tests passed, not 8, in this case):
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
def test_collect_symlinks_windows(pytester: Pytester, tmpdir) -> None:
"""Regression test for #12039: Tests collected multiple times under Windows."""
test_file = Path(tmpdir) / "symlink_collection_test.py"
test_file.write_text("def test(): pass", encoding="UTF-8")
result = pytester.runpytest(tmpdir)
> assert result.parseoutcomes() == {"passed": 1}
E AssertionError: assert {'passed': 2} == {'passed': 1}
E
E Differing items:
E {'passed': 2} != {'passed': 1}
E Use -v to get more diff
Activity
nicoddemus commentedon Feb 27, 2024
Hi @mrbean-bremen, thanks for the report!
Probably it is related to the fix for short paths... perhaps it is collecting the soft-links that
tmpdircreates? 🤔pytest/src/_pytest/pathlib.py
Lines 206 to 225 in 98b008f
Pin pytest 8 to version 8.0.1
mrbean-bremen commentedon Feb 28, 2024
@nicoddemus - could be... I have unsucessfully tried to reproduce this locally (using junctions), I may have another look later, maybe tomorrow.
Pin pytest 8 to version 8.0.1
mrbean-bremen commentedon Feb 29, 2024
I can confirm that removing the fix for short paths (e.g. the line that uses
os.path.samefilefor the match) fixes the problem in the CI. Still no luck to reproduce this locally.mrbean-bremen commentedon Mar 1, 2024
@nicoddemus: I think the test using
samefileis too broad, as it also finds symlinks and junctions, which we don't wont.I tested to adapt the check to filter out links and junctions to regular directories, which fixes the problem in the CI:
(
is_junctionis basically a copy of the Python 3.12 implementation ofos.path.junction).This does not not exclude links to other links to the same directory, but I would say that these are very unlikely cases.
Directly checking the short paths using
ctypesandGetShortPath(which might be more correct) is possible, but ugly...Please let me know if this makes sense...
nicoddemus commentedon Mar 1, 2024
Hmm it does make sense.
Just the
islinkcheck is enough to fix your CI? If so, I think we can easily just add this extra check. Junctions are more rare (I believe), so I think we can leave them out of this fix for now, as it requires extra steps (or we can just check for them in 3.12 at least).mrbean-bremen commentedon Mar 1, 2024
I wouldn't say that junctions are rare (I use them all the time under Windows, as you need admin rights to create symlinks there), but maybe they are indeed rare for use cases with pytest. I will check tomorrow, if the check for links is sufficient for the CI.
mrbean-bremen commentedon Mar 2, 2024
Ok, I checked. You were right - the problem is indeed solved with the
islinkcheck alone.nicoddemus commentedon Mar 2, 2024
Thanks @mrbean-bremen.
However I'm having trouble reproducing this in a test, this is what I came up with:
However this executes just 1 test in several pytest versions I tried:
7.4.4,8.0.1,8.0.2,main:Can you try to reproduce this problem outside
pytest-order's test suite?mrbean-bremen commentedon Mar 2, 2024
Looks like the problem happens only withpytester, e.g. if I run tests usingpytester.EDIT:
pytesteris not involved, actually.I have set up a minimal repository to show this.
The test is trivial:
and under Linux the output in the CI is as expected:
while under Windows I get:
which is quite a lot of duplication...
mrbean-bremen commentedon Mar 2, 2024
Actually I wrote a test very similar to yours, and it passed locally, but failed in the CI (though with 2 tests passed, not 8, in this case):
Do not collect symlinked tests under Windows
Do not collect symlinked tests under Windows
Do not collect symlinked tests under Windows
Do not collect symlinked tests under Windows
mrbean-bremen commentedon Mar 3, 2024
I made a PR for this.
Do not collect symlinked tests under Windows (#12050)
Do not collect symlinked tests under Windows (pytest-dev#12050)
Add changelog entry for pytest-dev#12039 and add Mulat Mekonen to AUT…