|
20 | 20 | from pip._vendor.packaging.specifiers import Specifier
|
21 | 21 | from pip._vendor.pkg_resources import RequirementParseError, parse_requirements
|
22 | 22 |
|
23 |
| -from pip._internal.download import is_archive_file, is_url, url_to_path |
| 23 | +from pip._internal.download import ( |
| 24 | + is_archive_file, is_url, path_to_url, url_to_path, |
| 25 | +) |
24 | 26 | from pip._internal.exceptions import InstallationError
|
25 | 27 | from pip._internal.models.index import PyPI, TestPyPI
|
26 | 28 | from pip._internal.models.link import Link
|
@@ -201,6 +203,58 @@ def install_req_from_editable(
|
201 | 203 | )
|
202 | 204 |
|
203 | 205 |
|
| 206 | +def _get_path_or_url(path, name): |
| 207 | + # type: (str, str) -> str |
| 208 | + """ |
| 209 | + First, it checks whether a provided path is an installable directory |
| 210 | + (e.g. it has a setup.py). If it is, returns the path. |
| 211 | +
|
| 212 | + If false, check if the path is an archive file (such as a .whl). |
| 213 | + The function checks if the path is a file. If false, if the path has |
| 214 | + an @, it will treat it as a PEP 440 URL requirement and return the path. |
| 215 | + """ |
| 216 | + if os.path.isdir(path) and _looks_like_path(name): |
| 217 | + if not is_installable_dir(path): |
| 218 | + raise InstallationError( |
| 219 | + "Directory %r is not installable. Neither 'setup.py' " |
| 220 | + "nor 'pyproject.toml' found." % name |
| 221 | + ) |
| 222 | + return path_to_url(path) |
| 223 | + elif is_archive_file(path): |
| 224 | + if os.path.isfile(path): |
| 225 | + return path_to_url(path) |
| 226 | + else: |
| 227 | + urlreq_parts = name.split('@', 1) |
| 228 | + if len(urlreq_parts) < 2 or _looks_like_path(urlreq_parts[0]): |
| 229 | + logger.warning( |
| 230 | + 'Requirement %r looks like a filename, but the ' |
| 231 | + 'file does not exist', |
| 232 | + name |
| 233 | + ) |
| 234 | + return path_to_url(path) |
| 235 | + # If the path contains '@' and the part before it does not look |
| 236 | + # like a path, try to treat it as a PEP 440 URL req instead. |
| 237 | + |
| 238 | + |
| 239 | +def _looks_like_path(name): |
| 240 | + # type: (str) -> bool |
| 241 | + """Checks whether the string "looks like" a path on the filesystem. |
| 242 | +
|
| 243 | + This does not check whether the target actually exists, only judge from the |
| 244 | + apperance. Returns true if any of the following is true: |
| 245 | +
|
| 246 | + * A path separator is found (either os.path.sep or os.path.altsep). |
| 247 | + * The string starts with "." (current directory). |
| 248 | + """ |
| 249 | + if os.path.sep in name: |
| 250 | + return True |
| 251 | + if os.path.altsep is not None and os.path.altsep in name: |
| 252 | + return True |
| 253 | + if name.startswith('.'): |
| 254 | + return True |
| 255 | + return False |
| 256 | + |
| 257 | + |
204 | 258 | def install_req_from_line(
|
205 | 259 | name, # type: str
|
206 | 260 | comes_from=None, # type: Optional[Union[str, InstallRequirement]]
|
@@ -241,26 +295,9 @@ def install_req_from_line(
|
241 | 295 | link = Link(name)
|
242 | 296 | else:
|
243 | 297 | p, extras_as_string = _strip_extras(path)
|
244 |
| - looks_like_dir = os.path.isdir(p) and ( |
245 |
| - os.path.sep in name or |
246 |
| - (os.path.altsep is not None and os.path.altsep in name) or |
247 |
| - name.startswith('.') |
248 |
| - ) |
249 |
| - if looks_like_dir: |
250 |
| - if not is_installable_dir(p): |
251 |
| - raise InstallationError( |
252 |
| - "Directory %r is not installable. Neither 'setup.py' " |
253 |
| - "nor 'pyproject.toml' found." % name |
254 |
| - ) |
255 |
| - link = Link(path_to_url(p)) |
256 |
| - elif is_archive_file(p): |
257 |
| - if not os.path.isfile(p): |
258 |
| - logger.warning( |
259 |
| - 'Requirement %r looks like a filename, but the ' |
260 |
| - 'file does not exist', |
261 |
| - name |
262 |
| - ) |
263 |
| - link = Link(path_to_url(p)) |
| 298 | + path_or_url = _get_path_or_url(p, name) |
| 299 | + if path_or_url: |
| 300 | + link = Link(path_or_url) |
264 | 301 |
|
265 | 302 | # it's a local file, dir, or url
|
266 | 303 | if link:
|
|
0 commit comments