Skip to content

Commit 17794fd

Browse files
authored
Expand long filename error hints on Windows (#13490)
Windows (or at least NTFS) isn't able to cope with paths where any *segment* is longer than 255 characters, even if Long Path Support is enabled. Update the hints provided on OS errors on Windows to reflect this possibility.
1 parent 644d6b1 commit 17794fd

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

news/13346.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Provide a hint if a system error is raised involving long filenames or path segments on Windows.

src/pip/_internal/commands/install.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import shutil
88
import site
99
from optparse import SUPPRESS_HELP, Values
10+
from pathlib import Path
1011

1112
from pip._vendor.packaging.utils import canonicalize_name
1213
from pip._vendor.requests.exceptions import InvalidProxyURL
@@ -774,20 +775,24 @@ def create_os_error_message(
774775
)
775776
parts.append(".\n")
776777

777-
# Suggest the user to enable Long Paths if path length is
778-
# more than 260
779-
if (
780-
WINDOWS
781-
and error.errno == errno.ENOENT
782-
and error.filename
783-
and len(error.filename) > 260
784-
):
785-
parts.append(
786-
"HINT: This error might have occurred since "
787-
"this system does not have Windows Long Path "
788-
"support enabled. You can find information on "
789-
"how to enable this at "
790-
"https://pip.pypa.io/warnings/enable-long-paths\n"
791-
)
778+
# On Windows, errors like EINVAL or ENOENT may occur
779+
# if a file or folder name exceeds 255 characters,
780+
# or if the full path exceeds 260 characters and long path support isn't enabled.
781+
# This condition checks for such cases and adds a hint to the error output.
792782

783+
if WINDOWS and error.errno in (errno.EINVAL, errno.ENOENT) and error.filename:
784+
if any(len(part) > 255 for part in Path(error.filename).parts):
785+
parts.append(
786+
"HINT: This error might be caused by a file or folder name exceeding "
787+
"255 characters, which is a Windows limitation even if long paths "
788+
"are enabled.\n "
789+
)
790+
if len(error.filename) > 260:
791+
parts.append(
792+
"HINT: This error might have occurred since "
793+
"this system does not have Windows Long Path "
794+
"support enabled. You can find information on "
795+
"how to enable this at "
796+
"https://pip.pypa.io/warnings/enable-long-paths\n"
797+
)
793798
return "".join(parts).strip() + "\n"

tests/unit/test_command_install.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import errno
2+
import sys
23
from unittest import mock
34

45
import pytest
@@ -120,6 +121,56 @@ def test_most_cases(
120121
"Consider checking your local proxy configuration"
121122
' with "pip config debug".\n',
122123
),
124+
# Testing both long path error (ENOENT)
125+
# and long file/folder name error (EINVAL) on Windows
126+
pytest.param(
127+
OSError(errno.ENOENT, "No such file or directory", f"C:{'/a'*261}"),
128+
False,
129+
False,
130+
"Could not install packages due to an OSError: "
131+
f"[Errno 2] No such file or directory: 'C:{'/a'*261}'\n"
132+
"HINT: This error might have occurred since "
133+
"this system does not have Windows Long Path "
134+
"support enabled. You can find information on "
135+
"how to enable this at "
136+
"https://pip.pypa.io/warnings/enable-long-paths\n",
137+
marks=pytest.mark.skipif(
138+
sys.platform != "win32", reason="Windows-specific filename length test"
139+
),
140+
),
141+
pytest.param(
142+
OSError(errno.EINVAL, "No such file or directory", f"C:/{'a'*256}"),
143+
False,
144+
False,
145+
"Could not install packages due to an OSError: "
146+
f"[Errno 22] No such file or directory: 'C:/{'a'*256}'\n"
147+
"HINT: This error might be caused by a file or folder name exceeding "
148+
"255 characters, which is a Windows limitation even if long paths "
149+
"are enabled.\n",
150+
marks=pytest.mark.skipif(
151+
sys.platform != "win32", reason="Windows-specific filename length test"
152+
),
153+
),
154+
pytest.param(
155+
OSError(
156+
errno.EINVAL, "No such file or directory", f"C:{'/a'*261}/{'b'*256}"
157+
),
158+
False,
159+
False,
160+
"Could not install packages due to an OSError: "
161+
f"[Errno 22] No such file or directory: 'C:{'/a' * 261}/{'b' * 256}'\n"
162+
"HINT: This error might be caused by a file or folder name exceeding "
163+
"255 characters, which is a Windows limitation even if long paths "
164+
"are enabled.\n "
165+
"HINT: This error might have occurred since "
166+
"this system does not have Windows Long Path "
167+
"support enabled. You can find information on "
168+
"how to enable this at "
169+
"https://pip.pypa.io/warnings/enable-long-paths\n",
170+
marks=pytest.mark.skipif(
171+
sys.platform != "win32", reason="Windows-specific filename length test"
172+
),
173+
),
123174
],
124175
)
125176
def test_create_os_error_message(

0 commit comments

Comments
 (0)