Compare also paths on Windows when considering ImportPathMismatchError
On Windows, os.path.samefile returns false for paths mounted in UNC paths which point to the same location. I couldn't reproduce the actual case reported, but looking at the code it seems this commit should fix the issue. Fix #7678 Fix #8076
This commit is contained in:
parent
902739cfc3
commit
572dfcd160
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed bug where ``ImportPathMismatchError`` would be raised for files compiled in
|
||||||
|
the host and loaded later from an UNC mounted path (Windows).
|
|
@ -543,7 +543,7 @@ def import_path(
|
||||||
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
|
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
is_same = os.path.samefile(str(path), module_file)
|
is_same = _is_same(str(path), module_file)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
is_same = False
|
is_same = False
|
||||||
|
|
||||||
|
@ -553,6 +553,20 @@ def import_path(
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
|
||||||
|
# Implement a special _is_same function on Windows which returns True if the two filenames
|
||||||
|
# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678).
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
|
||||||
|
def _is_same(f1: str, f2: str) -> bool:
|
||||||
|
return Path(f1) == Path(f2) or os.path.samefile(f1, f2)
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _is_same(f1: str, f2: str) -> bool:
|
||||||
|
return os.path.samefile(f1, f2)
|
||||||
|
|
||||||
|
|
||||||
def resolve_package_path(path: Path) -> Optional[Path]:
|
def resolve_package_path(path: Path) -> Optional[Path]:
|
||||||
"""Return the Python package path by looking for the last
|
"""Return the Python package path by looking for the last
|
||||||
directory upwards which still contains an __init__.py.
|
directory upwards which still contains an __init__.py.
|
||||||
|
|
|
@ -7,6 +7,7 @@ from textwrap import dedent
|
||||||
import py
|
import py
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
from _pytest.pathlib import bestrelpath
|
from _pytest.pathlib import bestrelpath
|
||||||
from _pytest.pathlib import commonpath
|
from _pytest.pathlib import commonpath
|
||||||
from _pytest.pathlib import ensure_deletable
|
from _pytest.pathlib import ensure_deletable
|
||||||
|
@ -414,3 +415,23 @@ def test_visit_ignores_errors(tmpdir) -> None:
|
||||||
"bar",
|
"bar",
|
||||||
"foo",
|
"foo",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
|
||||||
|
def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""
|
||||||
|
import_file() should not raise ImportPathMismatchError if the paths are exactly
|
||||||
|
equal on Windows. It seems directories mounted as UNC paths make os.path.samefile
|
||||||
|
return False, even when they are clearly equal.
|
||||||
|
"""
|
||||||
|
module_path = tmp_path.joinpath("my_module.py")
|
||||||
|
module_path.write_text("def foo(): return 42")
|
||||||
|
monkeypatch.syspath_prepend(tmp_path)
|
||||||
|
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
# Forcibly make os.path.samefile() return False here to ensure we are comparing
|
||||||
|
# the paths too. Using a context to narrow the patch as much as possible given
|
||||||
|
# this is an important system function.
|
||||||
|
mp.setattr(os.path, "samefile", lambda x, y: False)
|
||||||
|
module = import_path(module_path)
|
||||||
|
assert getattr(module, "foo")() == 42
|
||||||
|
|
Loading…
Reference in New Issue