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