##// END OF EJS Templates
error: implement __str__ on RevlogError to fix some output defects on Py3...
Augie Fackler -
r40985:f732889a default
parent child Browse files
Show More
@@ -1,336 +1,344
1 1 # error.py - Mercurial exceptions
2 2 #
3 3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """Mercurial exceptions.
9 9
10 10 This allows us to catch exceptions at higher levels without forcing
11 11 imports.
12 12 """
13 13
14 14 from __future__ import absolute_import
15 15
16 16 # Do not import anything but pycompat here, please
17 17 from . import pycompat
18 18
19 19 def _tobytes(exc):
20 20 """Byte-stringify exception in the same way as BaseException_str()"""
21 21 if not exc.args:
22 22 return b''
23 23 if len(exc.args) == 1:
24 24 return pycompat.bytestr(exc.args[0])
25 25 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
26 26
27 27 class Hint(object):
28 28 """Mix-in to provide a hint of an error
29 29
30 30 This should come first in the inheritance list to consume a hint and
31 31 pass remaining arguments to the exception class.
32 32 """
33 33 def __init__(self, *args, **kw):
34 34 self.hint = kw.pop(r'hint', None)
35 35 super(Hint, self).__init__(*args, **kw)
36 36
37 37 class StorageError(Hint, Exception):
38 38 """Raised when an error occurs in a storage layer.
39 39
40 40 Usually subclassed by a storage-specific exception.
41 41 """
42 42 __bytes__ = _tobytes
43 43
44 44 class RevlogError(StorageError):
45 45 __bytes__ = _tobytes
46 46
47 def __str__(self):
48 # avoid cycle, and directly implement unimethod for this
49 # __str__ to allow delaying the import of encoding until
50 # someone actually wants the __str__ of a RevlogError (which
51 # should be very rare).
52 from . import encoding
53 return encoding.unifromlocal(_tobytes(self))
54
47 55 class FilteredIndexError(IndexError):
48 56 __bytes__ = _tobytes
49 57
50 58 class LookupError(RevlogError, KeyError):
51 59 def __init__(self, name, index, message):
52 60 self.name = name
53 61 self.index = index
54 62 # this can't be called 'message' because at least some installs of
55 63 # Python 2.6+ complain about the 'message' property being deprecated
56 64 self.lookupmessage = message
57 65 if isinstance(name, bytes) and len(name) == 20:
58 66 from .node import short
59 67 name = short(name)
60 68 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
61 69
62 70 def __bytes__(self):
63 71 return RevlogError.__bytes__(self)
64 72
65 73 def __str__(self):
66 74 return RevlogError.__str__(self)
67 75
68 76 class AmbiguousPrefixLookupError(LookupError):
69 77 pass
70 78
71 79 class FilteredLookupError(LookupError):
72 80 pass
73 81
74 82 class ManifestLookupError(LookupError):
75 83 pass
76 84
77 85 class CommandError(Exception):
78 86 """Exception raised on errors in parsing the command line."""
79 87 __bytes__ = _tobytes
80 88
81 89 class InterventionRequired(Hint, Exception):
82 90 """Exception raised when a command requires human intervention."""
83 91 __bytes__ = _tobytes
84 92
85 93 class Abort(Hint, Exception):
86 94 """Raised if a command needs to print an error and exit."""
87 95 __bytes__ = _tobytes
88 96
89 97 class HookLoadError(Abort):
90 98 """raised when loading a hook fails, aborting an operation
91 99
92 100 Exists to allow more specialized catching."""
93 101
94 102 class HookAbort(Abort):
95 103 """raised when a validation hook fails, aborting an operation
96 104
97 105 Exists to allow more specialized catching."""
98 106
99 107 class ConfigError(Abort):
100 108 """Exception raised when parsing config files"""
101 109
102 110 class UpdateAbort(Abort):
103 111 """Raised when an update is aborted for destination issue"""
104 112
105 113 class MergeDestAbort(Abort):
106 114 """Raised when an update is aborted for destination issues"""
107 115
108 116 class NoMergeDestAbort(MergeDestAbort):
109 117 """Raised when an update is aborted because there is nothing to merge"""
110 118
111 119 class ManyMergeDestAbort(MergeDestAbort):
112 120 """Raised when an update is aborted because destination is ambiguous"""
113 121
114 122 class ResponseExpected(Abort):
115 123 """Raised when an EOF is received for a prompt"""
116 124 def __init__(self):
117 125 from .i18n import _
118 126 Abort.__init__(self, _('response expected'))
119 127
120 128 class OutOfBandError(Hint, Exception):
121 129 """Exception raised when a remote repo reports failure"""
122 130 __bytes__ = _tobytes
123 131
124 132 class ParseError(Hint, Exception):
125 133 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
126 134 __bytes__ = _tobytes
127 135
128 136 class PatchError(Exception):
129 137 __bytes__ = _tobytes
130 138
131 139 class UnknownIdentifier(ParseError):
132 140 """Exception raised when a {rev,file}set references an unknown identifier"""
133 141
134 142 def __init__(self, function, symbols):
135 143 from .i18n import _
136 144 ParseError.__init__(self, _("unknown identifier: %s") % function)
137 145 self.function = function
138 146 self.symbols = symbols
139 147
140 148 class RepoError(Hint, Exception):
141 149 __bytes__ = _tobytes
142 150
143 151 class RepoLookupError(RepoError):
144 152 pass
145 153
146 154 class FilteredRepoLookupError(RepoLookupError):
147 155 pass
148 156
149 157 class CapabilityError(RepoError):
150 158 pass
151 159
152 160 class RequirementError(RepoError):
153 161 """Exception raised if .hg/requires has an unknown entry."""
154 162
155 163 class StdioError(IOError):
156 164 """Raised if I/O to stdout or stderr fails"""
157 165
158 166 def __init__(self, err):
159 167 IOError.__init__(self, err.errno, err.strerror)
160 168
161 169 # no __bytes__() because error message is derived from the standard IOError
162 170
163 171 class UnsupportedMergeRecords(Abort):
164 172 def __init__(self, recordtypes):
165 173 from .i18n import _
166 174 self.recordtypes = sorted(recordtypes)
167 175 s = ' '.join(self.recordtypes)
168 176 Abort.__init__(
169 177 self, _('unsupported merge state records: %s') % s,
170 178 hint=_('see https://mercurial-scm.org/wiki/MergeStateRecords for '
171 179 'more information'))
172 180
173 181 class UnknownVersion(Abort):
174 182 """generic exception for aborting from an encounter with an unknown version
175 183 """
176 184
177 185 def __init__(self, msg, hint=None, version=None):
178 186 self.version = version
179 187 super(UnknownVersion, self).__init__(msg, hint=hint)
180 188
181 189 class LockError(IOError):
182 190 def __init__(self, errno, strerror, filename, desc):
183 191 IOError.__init__(self, errno, strerror, filename)
184 192 self.desc = desc
185 193
186 194 # no __bytes__() because error message is derived from the standard IOError
187 195
188 196 class LockHeld(LockError):
189 197 def __init__(self, errno, filename, desc, locker):
190 198 LockError.__init__(self, errno, 'Lock held', filename, desc)
191 199 self.locker = locker
192 200
193 201 class LockUnavailable(LockError):
194 202 pass
195 203
196 204 # LockError is for errors while acquiring the lock -- this is unrelated
197 205 class LockInheritanceContractViolation(RuntimeError):
198 206 __bytes__ = _tobytes
199 207
200 208 class ResponseError(Exception):
201 209 """Raised to print an error with part of output and exit."""
202 210 __bytes__ = _tobytes
203 211
204 212 class UnknownCommand(Exception):
205 213 """Exception raised if command is not in the command table."""
206 214 __bytes__ = _tobytes
207 215
208 216 class AmbiguousCommand(Exception):
209 217 """Exception raised if command shortcut matches more than one command."""
210 218 __bytes__ = _tobytes
211 219
212 220 # derived from KeyboardInterrupt to simplify some breakout code
213 221 class SignalInterrupt(KeyboardInterrupt):
214 222 """Exception raised on SIGTERM and SIGHUP."""
215 223
216 224 class SignatureError(Exception):
217 225 __bytes__ = _tobytes
218 226
219 227 class PushRaced(RuntimeError):
220 228 """An exception raised during unbundling that indicate a push race"""
221 229 __bytes__ = _tobytes
222 230
223 231 class ProgrammingError(Hint, RuntimeError):
224 232 """Raised if a mercurial (core or extension) developer made a mistake"""
225 233
226 234 def __init__(self, msg, *args, **kwargs):
227 235 # On Python 3, turn the message back into a string since this is
228 236 # an internal-only error that won't be printed except in a
229 237 # stack traces.
230 238 msg = pycompat.sysstr(msg)
231 239 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
232 240
233 241 __bytes__ = _tobytes
234 242
235 243 class WdirUnsupported(Exception):
236 244 """An exception which is raised when 'wdir()' is not supported"""
237 245 __bytes__ = _tobytes
238 246
239 247 # bundle2 related errors
240 248 class BundleValueError(ValueError):
241 249 """error raised when bundle2 cannot be processed"""
242 250 __bytes__ = _tobytes
243 251
244 252 class BundleUnknownFeatureError(BundleValueError):
245 253 def __init__(self, parttype=None, params=(), values=()):
246 254 self.parttype = parttype
247 255 self.params = params
248 256 self.values = values
249 257 if self.parttype is None:
250 258 msg = 'Stream Parameter'
251 259 else:
252 260 msg = parttype
253 261 entries = self.params
254 262 if self.params and self.values:
255 263 assert len(self.params) == len(self.values)
256 264 entries = []
257 265 for idx, par in enumerate(self.params):
258 266 val = self.values[idx]
259 267 if val is None:
260 268 entries.append(val)
261 269 else:
262 270 entries.append("%s=%r" % (par, pycompat.maybebytestr(val)))
263 271 if entries:
264 272 msg = '%s - %s' % (msg, ', '.join(entries))
265 273 ValueError.__init__(self, msg)
266 274
267 275 class ReadOnlyPartError(RuntimeError):
268 276 """error raised when code tries to alter a part being generated"""
269 277 __bytes__ = _tobytes
270 278
271 279 class PushkeyFailed(Abort):
272 280 """error raised when a pushkey part failed to update a value"""
273 281
274 282 def __init__(self, partid, namespace=None, key=None, new=None, old=None,
275 283 ret=None):
276 284 self.partid = partid
277 285 self.namespace = namespace
278 286 self.key = key
279 287 self.new = new
280 288 self.old = old
281 289 self.ret = ret
282 290 # no i18n expected to be processed into a better message
283 291 Abort.__init__(self, 'failed to update value for "%s/%s"'
284 292 % (namespace, key))
285 293
286 294 class CensoredNodeError(StorageError):
287 295 """error raised when content verification fails on a censored node
288 296
289 297 Also contains the tombstone data substituted for the uncensored data.
290 298 """
291 299
292 300 def __init__(self, filename, node, tombstone):
293 301 from .node import short
294 302 StorageError.__init__(self, '%s:%s' % (filename, short(node)))
295 303 self.tombstone = tombstone
296 304
297 305 class CensoredBaseError(StorageError):
298 306 """error raised when a delta is rejected because its base is censored
299 307
300 308 A delta based on a censored revision must be formed as single patch
301 309 operation which replaces the entire base with new content. This ensures
302 310 the delta may be applied by clones which have not censored the base.
303 311 """
304 312
305 313 class InvalidBundleSpecification(Exception):
306 314 """error raised when a bundle specification is invalid.
307 315
308 316 This is used for syntax errors as opposed to support errors.
309 317 """
310 318 __bytes__ = _tobytes
311 319
312 320 class UnsupportedBundleSpecification(Exception):
313 321 """error raised when a bundle specification is not supported."""
314 322 __bytes__ = _tobytes
315 323
316 324 class CorruptedState(Exception):
317 325 """error raised when a command is not able to read its state from file"""
318 326 __bytes__ = _tobytes
319 327
320 328 class PeerTransportError(Abort):
321 329 """Transport-level I/O error when communicating with a peer repo."""
322 330
323 331 class InMemoryMergeConflictsError(Exception):
324 332 """Exception raised when merge conflicts arose during an in-memory merge."""
325 333 __bytes__ = _tobytes
326 334
327 335 class WireprotoCommandError(Exception):
328 336 """Represents an error during execution of a wire protocol command.
329 337
330 338 Should only be thrown by wire protocol version 2 commands.
331 339
332 340 The error is a formatter string and an optional iterable of arguments.
333 341 """
334 342 def __init__(self, message, args=None):
335 343 self.message = message
336 344 self.messageargs = args
General Comments 0
You need to be logged in to leave comments. Login now