31
31
from pip ._internal .vcs import is_url , vcs
32
32
33
33
__all__ = [
34
- "install_req_from_editable" , "install_req_from_line" ,
35
- "parse_editable"
34
+ "install_req_from_editable" ,
35
+ "install_req_from_line" ,
36
+ "parse_editable" ,
36
37
]
37
38
38
39
logger = logging .getLogger (__name__ )
39
40
operators = Specifier ._operators .keys ()
40
41
41
42
42
43
def _strip_extras (path : str ) -> Tuple [str , Optional [str ]]:
43
- m = re .match (r' ^(.+)(\[[^\]]+\])$' , path )
44
+ m = re .match (r" ^(.+)(\[[^\]]+\])$" , path )
44
45
extras = None
45
46
if m :
46
47
path_no_extras = m .group (1 )
@@ -74,26 +75,25 @@ def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
74
75
url_no_extras , extras = _strip_extras (url )
75
76
76
77
if os .path .isdir (url_no_extras ):
77
- setup_py = os .path .join (url_no_extras , ' setup.py' )
78
- setup_cfg = os .path .join (url_no_extras , ' setup.cfg' )
78
+ setup_py = os .path .join (url_no_extras , " setup.py" )
79
+ setup_cfg = os .path .join (url_no_extras , " setup.cfg" )
79
80
if not os .path .exists (setup_py ) and not os .path .exists (setup_cfg ):
80
81
msg = (
81
82
'File "setup.py" or "setup.cfg" not found. Directory cannot be '
82
- 'installed in editable mode: {}'
83
- .format (os .path .abspath (url_no_extras ))
83
+ "installed in editable mode: {}" .format (os .path .abspath (url_no_extras ))
84
84
)
85
85
pyproject_path = make_pyproject_path (url_no_extras )
86
86
if os .path .isfile (pyproject_path ):
87
87
msg += (
88
88
'\n (A "pyproject.toml" file was found, but editable '
89
- ' mode currently requires a setuptools-based build.)'
89
+ " mode currently requires a setuptools-based build.)"
90
90
)
91
91
raise InstallationError (msg )
92
92
93
93
# Treating it as code that has already been checked out
94
94
url_no_extras = path_to_url (url_no_extras )
95
95
96
- if url_no_extras .lower ().startswith (' file:' ):
96
+ if url_no_extras .lower ().startswith (" file:" ):
97
97
package_name = Link (url_no_extras ).egg_fragment
98
98
if extras :
99
99
return (
@@ -105,18 +105,18 @@ def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
105
105
return package_name , url_no_extras , set ()
106
106
107
107
for version_control in vcs :
108
- if url .lower ().startswith (f' { version_control } :' ):
109
- url = f' { version_control } +{ url } '
108
+ if url .lower ().startswith (f" { version_control } :" ):
109
+ url = f" { version_control } +{ url } "
110
110
break
111
111
112
112
link = Link (url )
113
113
114
114
if not link .is_vcs :
115
115
backends = ", " .join (vcs .all_schemes )
116
116
raise InstallationError (
117
- f' { editable_req } is not a valid editable requirement. '
118
- f' It should either be a path to a local project or a VCS URL '
119
- f' (beginning with { backends } ).'
117
+ f" { editable_req } is not a valid editable requirement. "
118
+ f" It should either be a path to a local project or a VCS URL "
119
+ f" (beginning with { backends } )."
120
120
)
121
121
122
122
package_name = link .egg_fragment
@@ -150,21 +150,19 @@ def deduce_helpful_msg(req: str) -> str:
150
150
" the packages specified within it."
151
151
).format (req )
152
152
except RequirementParseError :
153
- logger .debug (
154
- "Cannot parse '%s' as requirements file" , req , exc_info = True
155
- )
153
+ logger .debug ("Cannot parse '%s' as requirements file" , req , exc_info = True )
156
154
else :
157
155
msg += f" File '{ req } ' does not exist."
158
156
return msg
159
157
160
158
161
159
class RequirementParts :
162
160
def __init__ (
163
- self ,
164
- requirement : Optional [Requirement ],
165
- link : Optional [Link ],
166
- markers : Optional [Marker ],
167
- extras : Set [str ],
161
+ self ,
162
+ requirement : Optional [Requirement ],
163
+ link : Optional [Link ],
164
+ markers : Optional [Marker ],
165
+ extras : Set [str ],
168
166
):
169
167
self .requirement = requirement
170
168
self .link = link
@@ -258,24 +256,23 @@ def _get_url_from_path(path: str, name: str) -> Optional[str]:
258
256
return None
259
257
if os .path .isfile (path ):
260
258
return path_to_url (path )
261
- urlreq_parts = name .split ('@' , 1 )
259
+ urlreq_parts = name .split ("@" , 1 )
262
260
if len (urlreq_parts ) >= 2 and not _looks_like_path (urlreq_parts [0 ]):
263
261
# If the path contains '@' and the part before it does not look
264
262
# like a path, try to treat it as a PEP 440 URL req instead.
265
263
return None
266
264
logger .warning (
267
- 'Requirement %r looks like a filename, but the '
268
- 'file does not exist' ,
269
- name
265
+ "Requirement %r looks like a filename, but the file does not exist" ,
266
+ name ,
270
267
)
271
268
return path_to_url (path )
272
269
273
270
274
271
def parse_req_from_line (name : str , line_source : Optional [str ]) -> RequirementParts :
275
272
if is_url (name ):
276
- marker_sep = '; '
273
+ marker_sep = "; "
277
274
else :
278
- marker_sep = ';'
275
+ marker_sep = ";"
279
276
if marker_sep in name :
280
277
name , markers_as_string = name .split (marker_sep , 1 )
281
278
markers_as_string = markers_as_string .strip ()
@@ -302,9 +299,8 @@ def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementPar
302
299
# it's a local file, dir, or url
303
300
if link :
304
301
# Handle relative file URLs
305
- if link .scheme == 'file' and re .search (r'\.\./' , link .url ):
306
- link = Link (
307
- path_to_url (os .path .normpath (os .path .abspath (link .path ))))
302
+ if link .scheme == "file" and re .search (r"\.\./" , link .url ):
303
+ link = Link (path_to_url (os .path .normpath (os .path .abspath (link .path ))))
308
304
# wheel file
309
305
if link .is_wheel :
310
306
wheel = Wheel (link .filename ) # can raise InvalidWheelFilename
@@ -323,7 +319,7 @@ def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementPar
323
319
def with_source (text : str ) -> str :
324
320
if not line_source :
325
321
return text
326
- return f' { text } (from { line_source } )'
322
+ return f" { text } (from { line_source } )"
327
323
328
324
def _parse_req_string (req_as_string : str ) -> Requirement :
329
325
try :
@@ -332,16 +328,15 @@ def _parse_req_string(req_as_string: str) -> Requirement:
332
328
if os .path .sep in req_as_string :
333
329
add_msg = "It looks like a path."
334
330
add_msg += deduce_helpful_msg (req_as_string )
335
- elif ('=' in req_as_string and
336
- not any (op in req_as_string for op in operators )):
331
+ elif "=" in req_as_string and not any (
332
+ op in req_as_string for op in operators
333
+ ):
337
334
add_msg = "= is not a valid operator. Did you mean == ?"
338
335
else :
339
- add_msg = ''
340
- msg = with_source (
341
- f'Invalid requirement: { req_as_string !r} '
342
- )
336
+ add_msg = ""
337
+ msg = with_source (f"Invalid requirement: { req_as_string !r} " )
343
338
if add_msg :
344
- msg += f' \n Hint: { add_msg } '
339
+ msg += f" \n Hint: { add_msg } "
345
340
raise InstallationError (msg )
346
341
else :
347
342
# Deprecate extras after specifiers: "name>=1.0[extras]"
@@ -350,7 +345,7 @@ def _parse_req_string(req_as_string: str) -> Requirement:
350
345
# RequirementParts
351
346
for spec in req .specifier :
352
347
spec_str = str (spec )
353
- if spec_str .endswith (']' ):
348
+ if spec_str .endswith ("]" ):
354
349
msg = f"Extras after version '{ spec_str } '."
355
350
raise InstallationError (msg )
356
351
return req
@@ -382,8 +377,12 @@ def install_req_from_line(
382
377
parts = parse_req_from_line (name , line_source )
383
378
384
379
return InstallRequirement (
385
- parts .requirement , comes_from , link = parts .link , markers = parts .markers ,
386
- use_pep517 = use_pep517 , isolated = isolated ,
380
+ parts .requirement ,
381
+ comes_from ,
382
+ link = parts .link ,
383
+ markers = parts .markers ,
384
+ use_pep517 = use_pep517 ,
385
+ isolated = isolated ,
387
386
install_options = options .get ("install_options" , []) if options else [],
388
387
global_options = options .get ("global_options" , []) if options else [],
389
388
hash_options = options .get ("hashes" , {}) if options else {},
@@ -409,8 +408,12 @@ def install_req_from_req_string(
409
408
PyPI .file_storage_domain ,
410
409
TestPyPI .file_storage_domain ,
411
410
]
412
- if (req .url and comes_from and comes_from .link and
413
- comes_from .link .netloc in domains_not_allowed ):
411
+ if (
412
+ req .url
413
+ and comes_from
414
+ and comes_from .link
415
+ and comes_from .link .netloc in domains_not_allowed
416
+ ):
414
417
# Explicitly disallow pypi packages that depend on external urls
415
418
raise InstallationError (
416
419
"Packages installed from PyPI cannot depend on packages "
0 commit comments