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) |