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