Mercurial > repos > guerler > hhblits
comparison lib/python3.8/site-packages/pip/_internal/models/link.py @ 0:9e54283cc701 draft
"planemo upload commit d12c32a45bcd441307e632fca6d9af7d60289d44"
| author | guerler |
|---|---|
| date | Mon, 27 Jul 2020 03:47:31 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:9e54283cc701 |
|---|---|
| 1 import os | |
| 2 import posixpath | |
| 3 import re | |
| 4 | |
| 5 from pip._vendor.six.moves.urllib import parse as urllib_parse | |
| 6 | |
| 7 from pip._internal.utils.filetypes import WHEEL_EXTENSION | |
| 8 from pip._internal.utils.misc import ( | |
| 9 redact_auth_from_url, | |
| 10 split_auth_from_netloc, | |
| 11 splitext, | |
| 12 ) | |
| 13 from pip._internal.utils.models import KeyBasedCompareMixin | |
| 14 from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
| 15 from pip._internal.utils.urls import path_to_url, url_to_path | |
| 16 | |
| 17 if MYPY_CHECK_RUNNING: | |
| 18 from typing import Optional, Text, Tuple, Union | |
| 19 from pip._internal.index.collector import HTMLPage | |
| 20 from pip._internal.utils.hashes import Hashes | |
| 21 | |
| 22 | |
| 23 class Link(KeyBasedCompareMixin): | |
| 24 """Represents a parsed link from a Package Index's simple URL | |
| 25 """ | |
| 26 | |
| 27 def __init__( | |
| 28 self, | |
| 29 url, # type: str | |
| 30 comes_from=None, # type: Optional[Union[str, HTMLPage]] | |
| 31 requires_python=None, # type: Optional[str] | |
| 32 yanked_reason=None, # type: Optional[Text] | |
| 33 ): | |
| 34 # type: (...) -> None | |
| 35 """ | |
| 36 :param url: url of the resource pointed to (href of the link) | |
| 37 :param comes_from: instance of HTMLPage where the link was found, | |
| 38 or string. | |
| 39 :param requires_python: String containing the `Requires-Python` | |
| 40 metadata field, specified in PEP 345. This may be specified by | |
| 41 a data-requires-python attribute in the HTML link tag, as | |
| 42 described in PEP 503. | |
| 43 :param yanked_reason: the reason the file has been yanked, if the | |
| 44 file has been yanked, or None if the file hasn't been yanked. | |
| 45 This is the value of the "data-yanked" attribute, if present, in | |
| 46 a simple repository HTML link. If the file has been yanked but | |
| 47 no reason was provided, this should be the empty string. See | |
| 48 PEP 592 for more information and the specification. | |
| 49 """ | |
| 50 | |
| 51 # url can be a UNC windows share | |
| 52 if url.startswith('\\\\'): | |
| 53 url = path_to_url(url) | |
| 54 | |
| 55 self._parsed_url = urllib_parse.urlsplit(url) | |
| 56 # Store the url as a private attribute to prevent accidentally | |
| 57 # trying to set a new value. | |
| 58 self._url = url | |
| 59 | |
| 60 self.comes_from = comes_from | |
| 61 self.requires_python = requires_python if requires_python else None | |
| 62 self.yanked_reason = yanked_reason | |
| 63 | |
| 64 super(Link, self).__init__(key=url, defining_class=Link) | |
| 65 | |
| 66 def __str__(self): | |
| 67 # type: () -> str | |
| 68 if self.requires_python: | |
| 69 rp = ' (requires-python:%s)' % self.requires_python | |
| 70 else: | |
| 71 rp = '' | |
| 72 if self.comes_from: | |
| 73 return '%s (from %s)%s' % (redact_auth_from_url(self._url), | |
| 74 self.comes_from, rp) | |
| 75 else: | |
| 76 return redact_auth_from_url(str(self._url)) | |
| 77 | |
| 78 def __repr__(self): | |
| 79 # type: () -> str | |
| 80 return '<Link %s>' % self | |
| 81 | |
| 82 @property | |
| 83 def url(self): | |
| 84 # type: () -> str | |
| 85 return self._url | |
| 86 | |
| 87 @property | |
| 88 def filename(self): | |
| 89 # type: () -> str | |
| 90 path = self.path.rstrip('/') | |
| 91 name = posixpath.basename(path) | |
| 92 if not name: | |
| 93 # Make sure we don't leak auth information if the netloc | |
| 94 # includes a username and password. | |
| 95 netloc, user_pass = split_auth_from_netloc(self.netloc) | |
| 96 return netloc | |
| 97 | |
| 98 name = urllib_parse.unquote(name) | |
| 99 assert name, ('URL %r produced no filename' % self._url) | |
| 100 return name | |
| 101 | |
| 102 @property | |
| 103 def file_path(self): | |
| 104 # type: () -> str | |
| 105 return url_to_path(self.url) | |
| 106 | |
| 107 @property | |
| 108 def scheme(self): | |
| 109 # type: () -> str | |
| 110 return self._parsed_url.scheme | |
| 111 | |
| 112 @property | |
| 113 def netloc(self): | |
| 114 # type: () -> str | |
| 115 """ | |
| 116 This can contain auth information. | |
| 117 """ | |
| 118 return self._parsed_url.netloc | |
| 119 | |
| 120 @property | |
| 121 def path(self): | |
| 122 # type: () -> str | |
| 123 return urllib_parse.unquote(self._parsed_url.path) | |
| 124 | |
| 125 def splitext(self): | |
| 126 # type: () -> Tuple[str, str] | |
| 127 return splitext(posixpath.basename(self.path.rstrip('/'))) | |
| 128 | |
| 129 @property | |
| 130 def ext(self): | |
| 131 # type: () -> str | |
| 132 return self.splitext()[1] | |
| 133 | |
| 134 @property | |
| 135 def url_without_fragment(self): | |
| 136 # type: () -> str | |
| 137 scheme, netloc, path, query, fragment = self._parsed_url | |
| 138 return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) | |
| 139 | |
| 140 _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') | |
| 141 | |
| 142 @property | |
| 143 def egg_fragment(self): | |
| 144 # type: () -> Optional[str] | |
| 145 match = self._egg_fragment_re.search(self._url) | |
| 146 if not match: | |
| 147 return None | |
| 148 return match.group(1) | |
| 149 | |
| 150 _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') | |
| 151 | |
| 152 @property | |
| 153 def subdirectory_fragment(self): | |
| 154 # type: () -> Optional[str] | |
| 155 match = self._subdirectory_fragment_re.search(self._url) | |
| 156 if not match: | |
| 157 return None | |
| 158 return match.group(1) | |
| 159 | |
| 160 _hash_re = re.compile( | |
| 161 r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' | |
| 162 ) | |
| 163 | |
| 164 @property | |
| 165 def hash(self): | |
| 166 # type: () -> Optional[str] | |
| 167 match = self._hash_re.search(self._url) | |
| 168 if match: | |
| 169 return match.group(2) | |
| 170 return None | |
| 171 | |
| 172 @property | |
| 173 def hash_name(self): | |
| 174 # type: () -> Optional[str] | |
| 175 match = self._hash_re.search(self._url) | |
| 176 if match: | |
| 177 return match.group(1) | |
| 178 return None | |
| 179 | |
| 180 @property | |
| 181 def show_url(self): | |
| 182 # type: () -> str | |
| 183 return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0]) | |
| 184 | |
| 185 @property | |
| 186 def is_file(self): | |
| 187 # type: () -> bool | |
| 188 return self.scheme == 'file' | |
| 189 | |
| 190 def is_existing_dir(self): | |
| 191 # type: () -> bool | |
| 192 return self.is_file and os.path.isdir(self.file_path) | |
| 193 | |
| 194 @property | |
| 195 def is_wheel(self): | |
| 196 # type: () -> bool | |
| 197 return self.ext == WHEEL_EXTENSION | |
| 198 | |
| 199 @property | |
| 200 def is_vcs(self): | |
| 201 # type: () -> bool | |
| 202 from pip._internal.vcs import vcs | |
| 203 | |
| 204 return self.scheme in vcs.all_schemes | |
| 205 | |
| 206 @property | |
| 207 def is_yanked(self): | |
| 208 # type: () -> bool | |
| 209 return self.yanked_reason is not None | |
| 210 | |
| 211 @property | |
| 212 def has_hash(self): | |
| 213 # type: () -> bool | |
| 214 return self.hash_name is not None | |
| 215 | |
| 216 def is_hash_allowed(self, hashes): | |
| 217 # type: (Optional[Hashes]) -> bool | |
| 218 """ | |
| 219 Return True if the link has a hash and it is allowed. | |
| 220 """ | |
| 221 if hashes is None or not self.has_hash: | |
| 222 return False | |
| 223 # Assert non-None so mypy knows self.hash_name and self.hash are str. | |
| 224 assert self.hash_name is not None | |
| 225 assert self.hash is not None | |
| 226 | |
| 227 return hashes.is_hash_allowed(self.hash_name, hex_digest=self.hash) |
