File tree Expand file tree Collapse file tree 4 files changed +42
-11
lines changed Expand file tree Collapse file tree 4 files changed +42
-11
lines changed Original file line number Diff line number Diff line change
1
+ Strip leading slash from a ``file:// `` URL built from an path with the Windows
2
+ drive notation. This fixes bugs where the ``file:// `` URL cannot be correctly
3
+ used as requirement, constraint, or index URLs on Windows.
Original file line number Diff line number Diff line change 16
16
from pip ._internal .network .session import PipSession
17
17
from pip ._internal .network .utils import raise_for_status
18
18
from pip ._internal .utils .encoding import auto_decode
19
- from pip ._internal .utils .urls import get_url_scheme , url_to_path
19
+ from pip ._internal .utils .urls import get_url_scheme
20
20
21
21
if TYPE_CHECKING :
22
22
# NoReturn introduced in 3.6.2; imported only for type checking to maintain
@@ -532,20 +532,16 @@ def get_file_content(url, session):
532
532
"""
533
533
scheme = get_url_scheme (url )
534
534
535
- if scheme in [ 'http' , 'https' ]:
536
- # FIXME: catch some errors
535
+ # Pip has special support for file:// URLs (LocalFSAdapter).
536
+ if scheme in [ 'http' , 'https' , 'file' ]:
537
537
resp = session .get (url )
538
538
raise_for_status (resp )
539
539
return resp .url , resp .text
540
540
541
- elif scheme == 'file' :
542
- url = url_to_path (url )
543
-
541
+ # Assume this is a bare path.
544
542
try :
545
543
with open (url , 'rb' ) as f :
546
544
content = auto_decode (f .read ())
547
545
except OSError as exc :
548
- raise InstallationError (
549
- f'Could not open requirements file: { exc } '
550
- )
546
+ raise InstallationError (f'Could not open requirements file: { exc } ' )
551
547
return url , content
Original file line number Diff line number Diff line change 1
1
import os
2
- import sys
2
+ import string
3
3
import urllib .parse
4
4
import urllib .request
5
5
from typing import Optional
6
6
7
+ from .compat import WINDOWS
8
+
7
9
8
10
def get_url_scheme (url ):
9
11
# type: (str) -> Optional[str]
@@ -37,7 +39,7 @@ def url_to_path(url):
37
39
if not netloc or netloc == "localhost" :
38
40
# According to RFC 8089, same as empty authority.
39
41
netloc = ""
40
- elif sys . platform == "win32" :
42
+ elif WINDOWS :
41
43
# If we have a UNC path, prepend UNC share notation.
42
44
netloc = "\\ \\ " + netloc
43
45
else :
@@ -46,4 +48,18 @@ def url_to_path(url):
46
48
)
47
49
48
50
path = urllib .request .url2pathname (netloc + path )
51
+
52
+ # On Windows, urlsplit parses the path as something like "/C:/Users/foo".
53
+ # This creates issues for path-related functions like io.open(), so we try
54
+ # to detect and strip the leading slash.
55
+ if (
56
+ WINDOWS
57
+ and not netloc # Not UNC.
58
+ and len (path ) >= 3
59
+ and path [0 ] == "/" # Leading slash to strip.
60
+ and path [1 ] in string .ascii_letters # Drive letter.
61
+ and path [2 :4 ] in (":" , ":/" ) # Colon + end of string, or colon + absolute path.
62
+ ):
63
+ path = path [1 :]
64
+
49
65
return path
Original file line number Diff line number Diff line change @@ -67,6 +67,22 @@ def parse_reqfile(
67
67
)
68
68
69
69
70
+ def test_read_file_url (tmp_path ):
71
+ reqs = tmp_path .joinpath ("requirements.txt" )
72
+ reqs .write_text ("foo" )
73
+ result = list (parse_requirements (reqs .as_posix (), session ))
74
+
75
+ assert len (result ) == 1 , result
76
+ assert result [0 ].requirement == "foo"
77
+
78
+ # The comes_from value has three parts: -r or -c flag, path, and line.
79
+ # The path value in the middle needs some special logic due to our path
80
+ # normalization logic.
81
+ assert result [0 ].comes_from [:3 ] == "-r "
82
+ assert result [0 ].comes_from [- 9 :] == " (line 1)"
83
+ assert os .path .samefile (result [0 ].comes_from [3 :- 9 ], str (reqs ))
84
+
85
+
70
86
class TestPreprocess :
71
87
"""tests for `preprocess`"""
72
88
You can’t perform that action at this time.
0 commit comments