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