Skip to content

Commit e553b3a

Browse files
authored
Merge branch 'main' into 3.14
2 parents d425fcf + 4117dc7 commit e553b3a

File tree

5 files changed

+16
-49
lines changed

5 files changed

+16
-49
lines changed

news/13509.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix normalization of local links with non-``file`` schemes.

news/13510.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix normalization of local link on Windows in newer Python versions.

src/pip/_internal/models/link.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import os
77
import posixpath
88
import re
9-
import sys
109
import urllib.parse
1110
from collections.abc import Mapping
1211
from dataclasses import dataclass
@@ -133,8 +132,8 @@ def _clean_file_url_path(part: str) -> str:
133132
# exist, the colon should be quoted. We rely on urllib.request
134133
# to do the right thing here.
135134
ret = urllib.request.pathname2url(urllib.request.url2pathname(part))
136-
if sys.version_info >= (3, 14):
137-
# https://discuss.python.org/t/pathname2url-changes-in-python-3-14-breaking-pip-tests/97091
135+
if ret.startswith("///"):
136+
# Remove any URL authority section, leaving only the URL path.
138137
ret = ret.removeprefix("//")
139138
return ret
140139

@@ -177,7 +176,11 @@ def _ensure_quoted_url(url: str) -> str:
177176
# If the netloc is empty, then the URL refers to a local filesystem path.
178177
is_local_path = not result.netloc
179178
path = _clean_url_path(result.path, is_local_path=is_local_path)
180-
return urllib.parse.urlunsplit(result._replace(path=path))
179+
# Temporarily replace scheme with file to ensure the URL generated by
180+
# urlunsplit() contains an empty netloc (file://) as per RFC 1738.
181+
ret = urllib.parse.urlunsplit(result._replace(scheme="file", path=path))
182+
ret = result.scheme + ret[4:] # Restore original scheme.
183+
return ret
181184

182185

183186
def _absolute_link_url(base_url: str, url: str) -> str:

tests/lib/__init__.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from io import BytesIO, StringIO
1717
from textwrap import dedent
1818
from typing import Any, AnyStr, Callable, Literal, Protocol, Union, cast
19-
from urllib.parse import urlparse, urlunparse
2019
from urllib.request import pathname2url
2120
from zipfile import ZipFile
2221

@@ -1370,25 +1369,9 @@ def __call__(
13701369
# Accommodations for Windows path and URL changes in recent Python releases
13711370
# -------------------------------------------------------------------------
13721371

1373-
# versions containing fix/backport from https://github.com/python/cpython/pull/113563
1374-
# which changed the behavior of `urllib.parse.urlun{parse,split}`
1375-
url = "////path/to/file"
1376-
has_new_urlun_behavior = url == urlunparse(urlparse(url))
1377-
1378-
# the above change seems to only impact tests on Windows, so just add skips for that
1379-
skip_needs_new_urlun_behavior_win = pytest.mark.skipif(
1380-
sys.platform != "win32" or not has_new_urlun_behavior,
1381-
reason="testing windows behavior for newer CPython",
1382-
)
1383-
1384-
skip_needs_old_urlun_behavior_win = pytest.mark.skipif(
1385-
sys.platform != "win32" or has_new_urlun_behavior,
1386-
reason="testing windows behavior for older CPython",
1387-
)
1388-
13891372
# Trailing slashes are now preserved on Windows, matching POSIX behaviour.
13901373
# BPO: https://github.com/python/cpython/issues/126212
1391-
does_pathname2url_preserve_trailing_slash = pathname2url("C:/foo/").endswith("/")
1374+
does_pathname2url_preserve_trailing_slash = pathname2url("C:\\foo\\").endswith("/")
13921375
skip_needs_new_pathname2url_trailing_slash_behavior_win = pytest.mark.skipif(
13931376
sys.platform != "win32" or not does_pathname2url_preserve_trailing_slash,
13941377
reason="testing windows (pathname2url) behavior for newer CPython",

tests/unit/test_collector.py

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@
4242
TestData,
4343
make_test_link_collector,
4444
skip_needs_new_pathname2url_trailing_slash_behavior_win,
45-
skip_needs_new_urlun_behavior_win,
4645
skip_needs_old_pathname2url_trailing_slash_behavior_win,
47-
skip_needs_old_urlun_behavior_win,
4846
)
4947

5048
ACCEPT = ", ".join(
@@ -309,7 +307,7 @@ def test_clean_url_path(path: str, expected: str, is_local_path: bool) -> None:
309307
# Test a VCS path with a Windows drive letter and revision.
310308
pytest.param(
311309
"/T:/with space/[email protected]",
312-
"///T:/with%20space/[email protected]",
310+
"/T:/with%20space/[email protected]",
313311
marks=pytest.mark.skipif("sys.platform != 'win32'"),
314312
),
315313
# Test a VCS path with a Windows drive letter and revision,
@@ -393,26 +391,12 @@ def test_clean_url_path_with_local_path(path: str, expected: str) -> None:
393391
pytest.param(
394392
"file:///T:/path/with spaces/",
395393
"file:///T:/path/with%20spaces",
396-
marks=[
397-
skip_needs_old_urlun_behavior_win,
398-
skip_needs_old_pathname2url_trailing_slash_behavior_win,
399-
],
400-
),
401-
pytest.param(
402-
"file:///T:/path/with spaces/",
403-
"file://///T:/path/with%20spaces",
404-
marks=[
405-
skip_needs_new_urlun_behavior_win,
406-
skip_needs_old_pathname2url_trailing_slash_behavior_win,
407-
],
394+
marks=skip_needs_old_pathname2url_trailing_slash_behavior_win,
408395
),
409396
pytest.param(
410397
"file:///T:/path/with spaces/",
411-
"file://///T:/path/with%20spaces/",
412-
marks=[
413-
skip_needs_new_urlun_behavior_win,
414-
skip_needs_new_pathname2url_trailing_slash_behavior_win,
415-
],
398+
"file:///T:/path/with%20spaces/",
399+
marks=skip_needs_new_pathname2url_trailing_slash_behavior_win,
416400
),
417401
# URL with Windows drive letter, running on non-windows
418402
# platform. The `:` after the drive should be quoted.
@@ -425,18 +409,13 @@ def test_clean_url_path_with_local_path(path: str, expected: str) -> None:
425409
pytest.param(
426410
"git+file:///T:/with space/[email protected]#egg=my-package-1.0",
427411
"git+file:///T:/with%20space/[email protected]#egg=my-package-1.0",
428-
marks=skip_needs_old_urlun_behavior_win,
429-
),
430-
pytest.param(
431-
"git+file:///T:/with space/[email protected]#egg=my-package-1.0",
432-
"git+file://///T:/with%20space/[email protected]#egg=my-package-1.0",
433-
marks=skip_needs_new_urlun_behavior_win,
412+
marks=pytest.mark.skipif("sys.platform != 'win32'"),
434413
),
435414
# Test a VCS URL with a Windows drive letter and revision,
436415
# running on non-windows platform.
437416
pytest.param(
438417
"git+file:///T:/with space/[email protected]#egg=my-package-1.0",
439-
"git+file:/T%3A/with%20space/[email protected]#egg=my-package-1.0",
418+
"git+file:///T%3A/with%20space/[email protected]#egg=my-package-1.0",
440419
marks=pytest.mark.skipif("sys.platform == 'win32'"),
441420
),
442421
],

0 commit comments

Comments
 (0)