Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compare also paths on Windows when considering ImportPathMismatchError #8123

Merged
merged 1 commit into from Dec 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 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.
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