Skip to content

Commit 7e2e663

Browse files
authored
Merge pull request #8123 from nicoddemus/import-mismatch-unc
Compare also paths on Windows when considering ImportPathMismatchError
2 parents fa784e1 + 572dfcd commit 7e2e663

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

changelog/7678.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed bug where ``ImportPathMismatchError`` would be raised for files compiled in
2+
the host and loaded later from an UNC mounted path (Windows).

src/_pytest/pathlib.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ def import_path(
543543
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
544544

545545
try:
546-
is_same = os.path.samefile(str(path), module_file)
546+
is_same = _is_same(str(path), module_file)
547547
except FileNotFoundError:
548548
is_same = False
549549

@@ -553,6 +553,20 @@ def import_path(
553553
return mod
554554

555555

556+
# Implement a special _is_same function on Windows which returns True if the two filenames
557+
# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678).
558+
if sys.platform.startswith("win"):
559+
560+
def _is_same(f1: str, f2: str) -> bool:
561+
return Path(f1) == Path(f2) or os.path.samefile(f1, f2)
562+
563+
564+
else:
565+
566+
def _is_same(f1: str, f2: str) -> bool:
567+
return os.path.samefile(f1, f2)
568+
569+
556570
def resolve_package_path(path: Path) -> Optional[Path]:
557571
"""Return the Python package path by looking for the last
558572
directory upwards which still contains an __init__.py.

testing/test_pathlib.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import py
88

99
import pytest
10+
from _pytest.monkeypatch import MonkeyPatch
1011
from _pytest.pathlib import bestrelpath
1112
from _pytest.pathlib import commonpath
1213
from _pytest.pathlib import ensure_deletable
@@ -414,3 +415,23 @@ def test_visit_ignores_errors(tmpdir) -> None:
414415
"bar",
415416
"foo",
416417
]
418+
419+
420+
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
421+
def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
422+
"""
423+
import_file() should not raise ImportPathMismatchError if the paths are exactly
424+
equal on Windows. It seems directories mounted as UNC paths make os.path.samefile
425+
return False, even when they are clearly equal.
426+
"""
427+
module_path = tmp_path.joinpath("my_module.py")
428+
module_path.write_text("def foo(): return 42")
429+
monkeypatch.syspath_prepend(tmp_path)
430+
431+
with monkeypatch.context() as mp:
432+
# Forcibly make os.path.samefile() return False here to ensure we are comparing
433+
# the paths too. Using a context to narrow the patch as much as possible given
434+
# this is an important system function.
435+
mp.setattr(os.path, "samefile", lambda x, y: False)
436+
module = import_path(module_path)
437+
assert getattr(module, "foo")() == 42

0 commit comments

Comments
 (0)