summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Oliveira <nicoddemus@gmail.com>2020-12-12 08:49:58 -0300
committerBruno Oliveira <nicoddemus@gmail.com>2020-12-12 08:54:49 -0300
commit572dfcd160299489e66454de89a608da6f6d468e (patch)
treea9281360f385668a7da0f3bd058e99f178e7dc88
parent902739cfc3bbc3379e6ef99c8e250de35f52ecde (diff)
downloadpytest-572dfcd160299489e66454de89a608da6f6d468e.tar.gz
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
-rw-r--r--changelog/7678.bugfix.rst2
-rw-r--r--src/_pytest/pathlib.py16
-rw-r--r--testing/test_pathlib.py21
3 files changed, 38 insertions, 1 deletions
diff --git a/changelog/7678.bugfix.rst b/changelog/7678.bugfix.rst
new file mode 100644
index 000000000..4adc6ffd1
--- /dev/null
+++ b/changelog/7678.bugfix.rst
@@ -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).
diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py
index 6a36ae17a..8875a28f8 100644
--- a/src/_pytest/pathlib.py
+++ b/src/_pytest/pathlib.py
@@ -543,7 +543,7 @@ def import_path(
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
try:
- is_same = os.path.samefile(str(path), module_file)
+ is_same = _is_same(str(path), module_file)
except FileNotFoundError:
is_same = False
@@ -553,6 +553,20 @@ def import_path(
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]:
"""Return the Python package path by looking for the last
directory upwards which still contains an __init__.py.
diff --git a/testing/test_pathlib.py b/testing/test_pathlib.py
index 0507e3d68..f60b9f263 100644
--- a/testing/test_pathlib.py
+++ b/testing/test_pathlib.py
@@ -7,6 +7,7 @@ from textwrap import dedent
import py
import pytest
+from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import bestrelpath
from _pytest.pathlib import commonpath
from _pytest.pathlib import ensure_deletable
@@ -414,3 +415,23 @@ def test_visit_ignores_errors(tmpdir) -> None:
"bar",
"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