Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/pip/_internal/exceptions.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 """Exceptions used throughout package""" | |
2 from __future__ import absolute_import | |
3 | |
4 from itertools import chain, groupby, repeat | |
5 | |
6 from pip._vendor.six import iteritems | |
7 | |
8 from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
9 | |
10 if MYPY_CHECK_RUNNING: | |
11 from typing import Optional | |
12 from pip._vendor.pkg_resources import Distribution | |
13 from pip._internal.req.req_install import InstallRequirement | |
14 | |
15 | |
16 class PipError(Exception): | |
17 """Base pip exception""" | |
18 | |
19 | |
20 class ConfigurationError(PipError): | |
21 """General exception in configuration""" | |
22 | |
23 | |
24 class InstallationError(PipError): | |
25 """General exception during installation""" | |
26 | |
27 | |
28 class UninstallationError(PipError): | |
29 """General exception during uninstallation""" | |
30 | |
31 | |
32 class NoneMetadataError(PipError): | |
33 """ | |
34 Raised when accessing "METADATA" or "PKG-INFO" metadata for a | |
35 pip._vendor.pkg_resources.Distribution object and | |
36 `dist.has_metadata('METADATA')` returns True but | |
37 `dist.get_metadata('METADATA')` returns None (and similarly for | |
38 "PKG-INFO"). | |
39 """ | |
40 | |
41 def __init__(self, dist, metadata_name): | |
42 # type: (Distribution, str) -> None | |
43 """ | |
44 :param dist: A Distribution object. | |
45 :param metadata_name: The name of the metadata being accessed | |
46 (can be "METADATA" or "PKG-INFO"). | |
47 """ | |
48 self.dist = dist | |
49 self.metadata_name = metadata_name | |
50 | |
51 def __str__(self): | |
52 # type: () -> str | |
53 # Use `dist` in the error message because its stringification | |
54 # includes more information, like the version and location. | |
55 return ( | |
56 'None {} metadata found for distribution: {}'.format( | |
57 self.metadata_name, self.dist, | |
58 ) | |
59 ) | |
60 | |
61 | |
62 class DistributionNotFound(InstallationError): | |
63 """Raised when a distribution cannot be found to satisfy a requirement""" | |
64 | |
65 | |
66 class RequirementsFileParseError(InstallationError): | |
67 """Raised when a general error occurs parsing a requirements file line.""" | |
68 | |
69 | |
70 class BestVersionAlreadyInstalled(PipError): | |
71 """Raised when the most up-to-date version of a package is already | |
72 installed.""" | |
73 | |
74 | |
75 class BadCommand(PipError): | |
76 """Raised when virtualenv or a command is not found""" | |
77 | |
78 | |
79 class CommandError(PipError): | |
80 """Raised when there is an error in command-line arguments""" | |
81 | |
82 | |
83 class PreviousBuildDirError(PipError): | |
84 """Raised when there's a previous conflicting build directory""" | |
85 | |
86 | |
87 class InvalidWheelFilename(InstallationError): | |
88 """Invalid wheel filename.""" | |
89 | |
90 | |
91 class UnsupportedWheel(InstallationError): | |
92 """Unsupported wheel.""" | |
93 | |
94 | |
95 class HashErrors(InstallationError): | |
96 """Multiple HashError instances rolled into one for reporting""" | |
97 | |
98 def __init__(self): | |
99 self.errors = [] | |
100 | |
101 def append(self, error): | |
102 self.errors.append(error) | |
103 | |
104 def __str__(self): | |
105 lines = [] | |
106 self.errors.sort(key=lambda e: e.order) | |
107 for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): | |
108 lines.append(cls.head) | |
109 lines.extend(e.body() for e in errors_of_cls) | |
110 if lines: | |
111 return '\n'.join(lines) | |
112 | |
113 def __nonzero__(self): | |
114 return bool(self.errors) | |
115 | |
116 def __bool__(self): | |
117 return self.__nonzero__() | |
118 | |
119 | |
120 class HashError(InstallationError): | |
121 """ | |
122 A failure to verify a package against known-good hashes | |
123 | |
124 :cvar order: An int sorting hash exception classes by difficulty of | |
125 recovery (lower being harder), so the user doesn't bother fretting | |
126 about unpinned packages when he has deeper issues, like VCS | |
127 dependencies, to deal with. Also keeps error reports in a | |
128 deterministic order. | |
129 :cvar head: A section heading for display above potentially many | |
130 exceptions of this kind | |
131 :ivar req: The InstallRequirement that triggered this error. This is | |
132 pasted on after the exception is instantiated, because it's not | |
133 typically available earlier. | |
134 | |
135 """ | |
136 req = None # type: Optional[InstallRequirement] | |
137 head = '' | |
138 | |
139 def body(self): | |
140 """Return a summary of me for display under the heading. | |
141 | |
142 This default implementation simply prints a description of the | |
143 triggering requirement. | |
144 | |
145 :param req: The InstallRequirement that provoked this error, with | |
146 populate_link() having already been called | |
147 | |
148 """ | |
149 return ' %s' % self._requirement_name() | |
150 | |
151 def __str__(self): | |
152 return '%s\n%s' % (self.head, self.body()) | |
153 | |
154 def _requirement_name(self): | |
155 """Return a description of the requirement that triggered me. | |
156 | |
157 This default implementation returns long description of the req, with | |
158 line numbers | |
159 | |
160 """ | |
161 return str(self.req) if self.req else 'unknown package' | |
162 | |
163 | |
164 class VcsHashUnsupported(HashError): | |
165 """A hash was provided for a version-control-system-based requirement, but | |
166 we don't have a method for hashing those.""" | |
167 | |
168 order = 0 | |
169 head = ("Can't verify hashes for these requirements because we don't " | |
170 "have a way to hash version control repositories:") | |
171 | |
172 | |
173 class DirectoryUrlHashUnsupported(HashError): | |
174 """A hash was provided for a version-control-system-based requirement, but | |
175 we don't have a method for hashing those.""" | |
176 | |
177 order = 1 | |
178 head = ("Can't verify hashes for these file:// requirements because they " | |
179 "point to directories:") | |
180 | |
181 | |
182 class HashMissing(HashError): | |
183 """A hash was needed for a requirement but is absent.""" | |
184 | |
185 order = 2 | |
186 head = ('Hashes are required in --require-hashes mode, but they are ' | |
187 'missing from some requirements. Here is a list of those ' | |
188 'requirements along with the hashes their downloaded archives ' | |
189 'actually had. Add lines like these to your requirements files to ' | |
190 'prevent tampering. (If you did not enable --require-hashes ' | |
191 'manually, note that it turns on automatically when any package ' | |
192 'has a hash.)') | |
193 | |
194 def __init__(self, gotten_hash): | |
195 """ | |
196 :param gotten_hash: The hash of the (possibly malicious) archive we | |
197 just downloaded | |
198 """ | |
199 self.gotten_hash = gotten_hash | |
200 | |
201 def body(self): | |
202 # Dodge circular import. | |
203 from pip._internal.utils.hashes import FAVORITE_HASH | |
204 | |
205 package = None | |
206 if self.req: | |
207 # In the case of URL-based requirements, display the original URL | |
208 # seen in the requirements file rather than the package name, | |
209 # so the output can be directly copied into the requirements file. | |
210 package = (self.req.original_link if self.req.original_link | |
211 # In case someone feeds something downright stupid | |
212 # to InstallRequirement's constructor. | |
213 else getattr(self.req, 'req', None)) | |
214 return ' %s --hash=%s:%s' % (package or 'unknown package', | |
215 FAVORITE_HASH, | |
216 self.gotten_hash) | |
217 | |
218 | |
219 class HashUnpinned(HashError): | |
220 """A requirement had a hash specified but was not pinned to a specific | |
221 version.""" | |
222 | |
223 order = 3 | |
224 head = ('In --require-hashes mode, all requirements must have their ' | |
225 'versions pinned with ==. These do not:') | |
226 | |
227 | |
228 class HashMismatch(HashError): | |
229 """ | |
230 Distribution file hash values don't match. | |
231 | |
232 :ivar package_name: The name of the package that triggered the hash | |
233 mismatch. Feel free to write to this after the exception is raise to | |
234 improve its error message. | |
235 | |
236 """ | |
237 order = 4 | |
238 head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' | |
239 'FILE. If you have updated the package versions, please update ' | |
240 'the hashes. Otherwise, examine the package contents carefully; ' | |
241 'someone may have tampered with them.') | |
242 | |
243 def __init__(self, allowed, gots): | |
244 """ | |
245 :param allowed: A dict of algorithm names pointing to lists of allowed | |
246 hex digests | |
247 :param gots: A dict of algorithm names pointing to hashes we | |
248 actually got from the files under suspicion | |
249 """ | |
250 self.allowed = allowed | |
251 self.gots = gots | |
252 | |
253 def body(self): | |
254 return ' %s:\n%s' % (self._requirement_name(), | |
255 self._hash_comparison()) | |
256 | |
257 def _hash_comparison(self): | |
258 """ | |
259 Return a comparison of actual and expected hash values. | |
260 | |
261 Example:: | |
262 | |
263 Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde | |
264 or 123451234512345123451234512345123451234512345 | |
265 Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef | |
266 | |
267 """ | |
268 def hash_then_or(hash_name): | |
269 # For now, all the decent hashes have 6-char names, so we can get | |
270 # away with hard-coding space literals. | |
271 return chain([hash_name], repeat(' or')) | |
272 | |
273 lines = [] | |
274 for hash_name, expecteds in iteritems(self.allowed): | |
275 prefix = hash_then_or(hash_name) | |
276 lines.extend((' Expected %s %s' % (next(prefix), e)) | |
277 for e in expecteds) | |
278 lines.append(' Got %s\n' % | |
279 self.gots[hash_name].hexdigest()) | |
280 prefix = ' or' | |
281 return '\n'.join(lines) | |
282 | |
283 | |
284 class UnsupportedPythonVersion(InstallationError): | |
285 """Unsupported python version according to Requires-Python package | |
286 metadata.""" | |
287 | |
288 | |
289 class ConfigurationFileCouldNotBeLoaded(ConfigurationError): | |
290 """When there are errors while loading a configuration file | |
291 """ | |
292 | |
293 def __init__(self, reason="could not be loaded", fname=None, error=None): | |
294 super(ConfigurationFileCouldNotBeLoaded, self).__init__(error) | |
295 self.reason = reason | |
296 self.fname = fname | |
297 self.error = error | |
298 | |
299 def __str__(self): | |
300 if self.fname is not None: | |
301 message_part = " in {}.".format(self.fname) | |
302 else: | |
303 assert self.error is not None | |
304 message_part = ".\n{}\n".format(self.error.message) | |
305 return "Configuration file {}{}".format(self.reason, message_part) |