Skip to content

Commit abb43a6

Browse files
committed
Revert "Expand to long paths when resolving collection arguments"
This reverts commit 2e8f957.
1 parent 2e8f957 commit abb43a6

File tree

3 files changed

+29
-78
lines changed

3 files changed

+29
-78
lines changed

src/_pytest/compat.py

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# mypy: allow-untyped-defs
2-
"""Python version and platform compatibility code."""
2+
"""Python version compatibility code."""
33
from __future__ import annotations
44

55
import dataclasses
@@ -301,39 +301,6 @@ def get_user_id() -> int | None:
301301
return uid if uid != ERROR else None
302302

303303

304-
if sys.platform == "win32":
305-
from ctypes import create_unicode_buffer
306-
from ctypes import windll
307-
308-
def ensure_long_path(p: Path) -> Path:
309-
"""
310-
Returns the given path in its long form in Windows.
311-
312-
Short-paths follow the DOS restriction of 8 characters + 3 chars for file extension,
313-
and are still supported by Windows.
314-
"""
315-
# If the path does not exist, we cannot discover its long path.
316-
if not p.exists():
317-
return p
318-
short_path = os.fspath(p)
319-
# Use a buffer twice the size of the original path size to (reasonably) ensure we will be able
320-
# to hold the long path.
321-
buffer_size = len(short_path) * 2
322-
buffer = create_unicode_buffer(buffer_size)
323-
windll.kernel32.GetLongPathNameW(short_path, buffer, buffer_size)
324-
long_path_str = buffer.value
325-
# If we could not convert it, probably better to hard-crash this now rather
326-
# than later.
327-
assert long_path_str, f"Failed to convert short path to long path form:\n(size: {len(short_path)}):{short_path}"
328-
return Path(buffer.value)
329-
330-
else:
331-
332-
def ensure_long_path(p: Path) -> Path:
333-
"""No-op in other platforms."""
334-
return p
335-
336-
337304
# Perform exhaustiveness checking.
338305
#
339306
# Consider this example:

src/_pytest/main.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
from _pytest import nodes
3030
import _pytest._code
31-
from _pytest.compat import ensure_long_path
3231
from _pytest.config import Config
3332
from _pytest.config import directory_arg
3433
from _pytest.config import ExitCode
@@ -902,6 +901,10 @@ def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
902901
# Path part e.g. `/a/b/` in `/a/b/test_file.py::TestIt::test_it`.
903902
if isinstance(matchparts[0], Path):
904903
is_match = node.path == matchparts[0]
904+
if sys.platform == "win32" and not is_match:
905+
# In case the file paths do not match, fallback to samefile() to
906+
# account for short-paths on Windows (#11895).
907+
is_match = os.path.samefile(node.path, matchparts[0])
905908
# Name part e.g. `TestIt` in `/a/b/test_file.py::TestIt::test_it`.
906909
else:
907910
# TODO: Remove parametrized workaround once collection structure contains
@@ -1009,6 +1012,4 @@ def resolve_collection_argument(
10091012
else "directory argument cannot contain :: selection parts: {arg}"
10101013
)
10111014
raise UsageError(msg.format(arg=arg))
1012-
# Ensure we expand short paths to long paths on Windows (#11895).
1013-
fspath = ensure_long_path(fspath)
10141015
return fspath, parts

testing/test_collection.py

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from typing import List
1010

1111
from _pytest.assertion.util import running_on_ci
12-
from _pytest.compat import ensure_long_path
1312
from _pytest.config import ExitCode
1413
from _pytest.fixtures import FixtureRequest
1514
from _pytest.main import _in_venv
@@ -1764,43 +1763,27 @@ def test_foo(): assert True
17641763
assert result.parseoutcomes() == {"passed": 1}
17651764

17661765

1767-
class TestCollectionShortPaths:
1768-
@pytest.fixture
1769-
def short_path(self) -> Path:
1770-
short_path = tempfile.mkdtemp()
1771-
if "~" not in short_path: # pragma: no cover
1772-
if running_on_ci():
1773-
# On CI, we are expecting that under the current GitHub actions configuration,
1774-
# tempfile.mkdtemp() is producing short paths, so we want to fail to prevent
1775-
# this from silently changing without us noticing.
1776-
pytest.fail(
1777-
f"tempfile.mkdtemp() failed to produce a short path on CI: {short_path}"
1778-
)
1779-
else:
1780-
# We want to skip failing this test locally in this situation because
1781-
# depending on the local configuration tempfile.mkdtemp() might not produce a short path:
1782-
# For example, user might have configured %TEMP% exactly to avoid generating short paths.
1783-
pytest.skip(
1784-
f"tempfile.mkdtemp() failed to produce a short path: {short_path}, skipping"
1785-
)
1786-
return Path(short_path)
1787-
1788-
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
1789-
def test_ensure_long_path_win(self, short_path: Path) -> None:
1790-
long_path = ensure_long_path(short_path)
1791-
assert len(os.fspath(long_path)) > len(os.fspath(short_path))
1792-
1793-
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
1794-
def test_collect_short_file_windows(
1795-
self, pytester: Pytester, short_path: Path
1796-
) -> None:
1797-
"""Reproducer for #11895: short paths not collected on Windows."""
1798-
test_file = short_path.joinpath("test_collect_short_file_windows.py")
1799-
test_file.write_text("def test(): pass", encoding="UTF-8")
1800-
result = pytester.runpytest(short_path)
1801-
assert result.parseoutcomes() == {"passed": 1}
1802-
1803-
def test_ensure_long_path_general(self, tmp_path: Path) -> None:
1804-
"""Sanity check: a normal path to ensure_long_path works on all platforms."""
1805-
assert ensure_long_path(tmp_path) == tmp_path
1806-
assert ensure_long_path(tmp_path / "non-existent") == tmp_path / "non-existent"
1766+
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
1767+
def test_collect_short_file_windows(pytester: Pytester) -> None:
1768+
"""Reproducer for #11895: short paths not colleced on Windows."""
1769+
short_path = tempfile.mkdtemp()
1770+
if "~" not in short_path: # pragma: no cover
1771+
if running_on_ci():
1772+
# On CI, we are expecting that under the current GitHub actions configuration,
1773+
# tempfile.mkdtemp() is producing short paths, so we want to fail to prevent
1774+
# this from silently changing without us noticing.
1775+
pytest.fail(
1776+
f"tempfile.mkdtemp() failed to produce a short path on CI: {short_path}"
1777+
)
1778+
else:
1779+
# We want to skip failing this test locally in this situation because
1780+
# depending on the local configuration tempfile.mkdtemp() might not produce a short path:
1781+
# For example, user might have configured %TEMP% exactly to avoid generating short paths.
1782+
pytest.skip(
1783+
f"tempfile.mkdtemp() failed to produce a short path: {short_path}, skipping"
1784+
)
1785+
1786+
test_file = Path(short_path).joinpath("test_collect_short_file_windows.py")
1787+
test_file.write_text("def test(): pass", encoding="UTF-8")
1788+
result = pytester.runpytest(short_path)
1789+
assert result.parseoutcomes() == {"passed": 1}

0 commit comments

Comments
 (0)