Skip to content

Commit

Permalink
Compare also paths on Windows when considering ImportPathMismatchError
Browse files Browse the repository at this point in the history
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 pytest-dev#7678
Fix pytest-dev#8076
  • Loading branch information
nicoddemus committed Dec 12, 2020
1 parent 902739c commit 110729c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
2 changes: 2 additions & 0 deletions 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).
16 changes: 15 additions & 1 deletion src/_pytest/pathlib.py
Expand Up @@ -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

Expand All @@ -553,6 +553,20 @@ def import_path(
return mod


# Implement a special _is_same function on Windows which returns True if the two paths
# are equal. See #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.
Expand Down
21 changes: 21 additions & 0 deletions testing/test_pathlib.py
Expand Up @@ -7,6 +7,7 @@
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
Expand Down Expand Up @@ -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

0 comments on commit 110729c

Please sign in to comment.