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