##// END OF EJS Templates
error: unconditionally define __str__...
Gregory Szorc -
r49744:9baec00b default
parent child Browse files
Show More
@@ -1,676 +1,674 b''
1 # error.py - Mercurial exceptions
1 # error.py - Mercurial exceptions
2 #
2 #
3 # Copyright 2005-2008 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2008 Olivia Mackall <olivia@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
14
15 import difflib
15 import difflib
16
16
17 # Do not import anything but pycompat here, please
17 # Do not import anything but pycompat here, please
18 from . import pycompat
18 from . import pycompat
19
19
20 if pycompat.TYPE_CHECKING:
20 if pycompat.TYPE_CHECKING:
21 from typing import (
21 from typing import (
22 Any,
22 Any,
23 AnyStr,
23 AnyStr,
24 Iterable,
24 Iterable,
25 List,
25 List,
26 Optional,
26 Optional,
27 Sequence,
27 Sequence,
28 Union,
28 Union,
29 )
29 )
30
30
31
31
32 def _tobytes(exc):
32 def _tobytes(exc):
33 # type: (...) -> bytes
33 # type: (...) -> bytes
34 """Byte-stringify exception in the same way as BaseException_str()"""
34 """Byte-stringify exception in the same way as BaseException_str()"""
35 if not exc.args:
35 if not exc.args:
36 return b''
36 return b''
37 if len(exc.args) == 1:
37 if len(exc.args) == 1:
38 return pycompat.bytestr(exc.args[0])
38 return pycompat.bytestr(exc.args[0])
39 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
39 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
40
40
41
41
42 class Hint(object):
42 class Hint(object):
43 """Mix-in to provide a hint of an error
43 """Mix-in to provide a hint of an error
44
44
45 This should come first in the inheritance list to consume a hint and
45 This should come first in the inheritance list to consume a hint and
46 pass remaining arguments to the exception class.
46 pass remaining arguments to the exception class.
47 """
47 """
48
48
49 def __init__(self, *args, **kw):
49 def __init__(self, *args, **kw):
50 self.hint = kw.pop('hint', None) # type: Optional[bytes]
50 self.hint = kw.pop('hint', None) # type: Optional[bytes]
51 super(Hint, self).__init__(*args, **kw)
51 super(Hint, self).__init__(*args, **kw)
52
52
53
53
54 class Error(Hint, Exception):
54 class Error(Hint, Exception):
55 """Base class for Mercurial errors."""
55 """Base class for Mercurial errors."""
56
56
57 coarse_exit_code = None
57 coarse_exit_code = None
58 detailed_exit_code = None
58 detailed_exit_code = None
59
59
60 def __init__(self, message, hint=None):
60 def __init__(self, message, hint=None):
61 # type: (bytes, Optional[bytes]) -> None
61 # type: (bytes, Optional[bytes]) -> None
62 self.message = message
62 self.message = message
63 self.hint = hint
63 self.hint = hint
64 # Pass the message into the Exception constructor to help extensions
64 # Pass the message into the Exception constructor to help extensions
65 # that look for exc.args[0].
65 # that look for exc.args[0].
66 Exception.__init__(self, message)
66 Exception.__init__(self, message)
67
67
68 def __bytes__(self):
68 def __bytes__(self):
69 return self.message
69 return self.message
70
70
71 if pycompat.ispy3:
72
73 def __str__(self):
71 def __str__(self):
74 # type: () -> str
72 # type: () -> str
75 # the output would be unreadable if the message was translated,
73 # the output would be unreadable if the message was translated,
76 # but do not replace it with encoding.strfromlocal(), which
74 # but do not replace it with encoding.strfromlocal(), which
77 # may raise another exception.
75 # may raise another exception.
78 return pycompat.sysstr(self.__bytes__())
76 return pycompat.sysstr(self.__bytes__())
79
77
80 def format(self):
78 def format(self):
81 # type: () -> bytes
79 # type: () -> bytes
82 from .i18n import _
80 from .i18n import _
83
81
84 message = _(b"abort: %s\n") % self.message
82 message = _(b"abort: %s\n") % self.message
85 if self.hint:
83 if self.hint:
86 message += _(b"(%s)\n") % self.hint
84 message += _(b"(%s)\n") % self.hint
87 return message
85 return message
88
86
89
87
90 class Abort(Error):
88 class Abort(Error):
91 """Raised if a command needs to print an error and exit."""
89 """Raised if a command needs to print an error and exit."""
92
90
93
91
94 class StorageError(Error):
92 class StorageError(Error):
95 """Raised when an error occurs in a storage layer.
93 """Raised when an error occurs in a storage layer.
96
94
97 Usually subclassed by a storage-specific exception.
95 Usually subclassed by a storage-specific exception.
98 """
96 """
99
97
100 detailed_exit_code = 50
98 detailed_exit_code = 50
101
99
102
100
103 class RevlogError(StorageError):
101 class RevlogError(StorageError):
104 pass
102 pass
105
103
106
104
107 class SidedataHashError(RevlogError):
105 class SidedataHashError(RevlogError):
108 def __init__(self, key, expected, got):
106 def __init__(self, key, expected, got):
109 # type: (int, bytes, bytes) -> None
107 # type: (int, bytes, bytes) -> None
110 self.hint = None
108 self.hint = None
111 self.sidedatakey = key
109 self.sidedatakey = key
112 self.expecteddigest = expected
110 self.expecteddigest = expected
113 self.actualdigest = got
111 self.actualdigest = got
114
112
115
113
116 class FilteredIndexError(IndexError):
114 class FilteredIndexError(IndexError):
117 __bytes__ = _tobytes
115 __bytes__ = _tobytes
118
116
119
117
120 class LookupError(RevlogError, KeyError):
118 class LookupError(RevlogError, KeyError):
121 def __init__(self, name, index, message):
119 def __init__(self, name, index, message):
122 # type: (bytes, bytes, bytes) -> None
120 # type: (bytes, bytes, bytes) -> None
123 self.name = name
121 self.name = name
124 self.index = index
122 self.index = index
125 # this can't be called 'message' because at least some installs of
123 # this can't be called 'message' because at least some installs of
126 # Python 2.6+ complain about the 'message' property being deprecated
124 # Python 2.6+ complain about the 'message' property being deprecated
127 self.lookupmessage = message
125 self.lookupmessage = message
128 if isinstance(name, bytes) and len(name) == 20:
126 if isinstance(name, bytes) and len(name) == 20:
129 from .node import hex
127 from .node import hex
130
128
131 name = hex(name)
129 name = hex(name)
132 # if name is a binary node, it can be None
130 # if name is a binary node, it can be None
133 RevlogError.__init__(
131 RevlogError.__init__(
134 self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message)
132 self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message)
135 )
133 )
136
134
137 def __bytes__(self):
135 def __bytes__(self):
138 return RevlogError.__bytes__(self)
136 return RevlogError.__bytes__(self)
139
137
140 def __str__(self):
138 def __str__(self):
141 return RevlogError.__str__(self)
139 return RevlogError.__str__(self)
142
140
143
141
144 class AmbiguousPrefixLookupError(LookupError):
142 class AmbiguousPrefixLookupError(LookupError):
145 pass
143 pass
146
144
147
145
148 class FilteredLookupError(LookupError):
146 class FilteredLookupError(LookupError):
149 pass
147 pass
150
148
151
149
152 class ManifestLookupError(LookupError):
150 class ManifestLookupError(LookupError):
153 pass
151 pass
154
152
155
153
156 class CommandError(Exception):
154 class CommandError(Exception):
157 """Exception raised on errors in parsing the command line."""
155 """Exception raised on errors in parsing the command line."""
158
156
159 def __init__(self, command, message):
157 def __init__(self, command, message):
160 # type: (bytes, bytes) -> None
158 # type: (bytes, bytes) -> None
161 self.command = command
159 self.command = command
162 self.message = message
160 self.message = message
163 super(CommandError, self).__init__()
161 super(CommandError, self).__init__()
164
162
165 __bytes__ = _tobytes
163 __bytes__ = _tobytes
166
164
167
165
168 class UnknownCommand(Exception):
166 class UnknownCommand(Exception):
169 """Exception raised if command is not in the command table."""
167 """Exception raised if command is not in the command table."""
170
168
171 def __init__(self, command, all_commands=None):
169 def __init__(self, command, all_commands=None):
172 # type: (bytes, Optional[List[bytes]]) -> None
170 # type: (bytes, Optional[List[bytes]]) -> None
173 self.command = command
171 self.command = command
174 self.all_commands = all_commands
172 self.all_commands = all_commands
175 super(UnknownCommand, self).__init__()
173 super(UnknownCommand, self).__init__()
176
174
177 __bytes__ = _tobytes
175 __bytes__ = _tobytes
178
176
179
177
180 class AmbiguousCommand(Exception):
178 class AmbiguousCommand(Exception):
181 """Exception raised if command shortcut matches more than one command."""
179 """Exception raised if command shortcut matches more than one command."""
182
180
183 def __init__(self, prefix, matches):
181 def __init__(self, prefix, matches):
184 # type: (bytes, List[bytes]) -> None
182 # type: (bytes, List[bytes]) -> None
185 self.prefix = prefix
183 self.prefix = prefix
186 self.matches = matches
184 self.matches = matches
187 super(AmbiguousCommand, self).__init__()
185 super(AmbiguousCommand, self).__init__()
188
186
189 __bytes__ = _tobytes
187 __bytes__ = _tobytes
190
188
191
189
192 class WorkerError(Exception):
190 class WorkerError(Exception):
193 """Exception raised when a worker process dies."""
191 """Exception raised when a worker process dies."""
194
192
195 def __init__(self, status_code):
193 def __init__(self, status_code):
196 # type: (int) -> None
194 # type: (int) -> None
197 self.status_code = status_code
195 self.status_code = status_code
198 # Pass status code to superclass just so it becomes part of __bytes__
196 # Pass status code to superclass just so it becomes part of __bytes__
199 super(WorkerError, self).__init__(status_code)
197 super(WorkerError, self).__init__(status_code)
200
198
201 __bytes__ = _tobytes
199 __bytes__ = _tobytes
202
200
203
201
204 class InterventionRequired(Abort):
202 class InterventionRequired(Abort):
205 """Exception raised when a command requires human intervention."""
203 """Exception raised when a command requires human intervention."""
206
204
207 coarse_exit_code = 1
205 coarse_exit_code = 1
208 detailed_exit_code = 240
206 detailed_exit_code = 240
209
207
210 def format(self):
208 def format(self):
211 # type: () -> bytes
209 # type: () -> bytes
212 from .i18n import _
210 from .i18n import _
213
211
214 message = _(b"%s\n") % self.message
212 message = _(b"%s\n") % self.message
215 if self.hint:
213 if self.hint:
216 message += _(b"(%s)\n") % self.hint
214 message += _(b"(%s)\n") % self.hint
217 return message
215 return message
218
216
219
217
220 class ConflictResolutionRequired(InterventionRequired):
218 class ConflictResolutionRequired(InterventionRequired):
221 """Exception raised when a continuable command required merge conflict resolution."""
219 """Exception raised when a continuable command required merge conflict resolution."""
222
220
223 def __init__(self, opname):
221 def __init__(self, opname):
224 # type: (bytes) -> None
222 # type: (bytes) -> None
225 from .i18n import _
223 from .i18n import _
226
224
227 self.opname = opname
225 self.opname = opname
228 InterventionRequired.__init__(
226 InterventionRequired.__init__(
229 self,
227 self,
230 _(
228 _(
231 b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')"
229 b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')"
232 )
230 )
233 % opname,
231 % opname,
234 )
232 )
235
233
236
234
237 class InputError(Abort):
235 class InputError(Abort):
238 """Indicates that the user made an error in their input.
236 """Indicates that the user made an error in their input.
239
237
240 Examples: Invalid command, invalid flags, invalid revision.
238 Examples: Invalid command, invalid flags, invalid revision.
241 """
239 """
242
240
243 detailed_exit_code = 10
241 detailed_exit_code = 10
244
242
245
243
246 class StateError(Abort):
244 class StateError(Abort):
247 """Indicates that the operation might work if retried in a different state.
245 """Indicates that the operation might work if retried in a different state.
248
246
249 Examples: Unresolved merge conflicts, unfinished operations.
247 Examples: Unresolved merge conflicts, unfinished operations.
250 """
248 """
251
249
252 detailed_exit_code = 20
250 detailed_exit_code = 20
253
251
254
252
255 class CanceledError(Abort):
253 class CanceledError(Abort):
256 """Indicates that the user canceled the operation.
254 """Indicates that the user canceled the operation.
257
255
258 Examples: Close commit editor with error status, quit chistedit.
256 Examples: Close commit editor with error status, quit chistedit.
259 """
257 """
260
258
261 detailed_exit_code = 250
259 detailed_exit_code = 250
262
260
263
261
264 class SecurityError(Abort):
262 class SecurityError(Abort):
265 """Indicates that some aspect of security failed.
263 """Indicates that some aspect of security failed.
266
264
267 Examples: Bad server credentials, expired local credentials for network
265 Examples: Bad server credentials, expired local credentials for network
268 filesystem, mismatched GPG signature, DoS protection.
266 filesystem, mismatched GPG signature, DoS protection.
269 """
267 """
270
268
271 detailed_exit_code = 150
269 detailed_exit_code = 150
272
270
273
271
274 class HookLoadError(Abort):
272 class HookLoadError(Abort):
275 """raised when loading a hook fails, aborting an operation
273 """raised when loading a hook fails, aborting an operation
276
274
277 Exists to allow more specialized catching."""
275 Exists to allow more specialized catching."""
278
276
279
277
280 class HookAbort(Abort):
278 class HookAbort(Abort):
281 """raised when a validation hook fails, aborting an operation
279 """raised when a validation hook fails, aborting an operation
282
280
283 Exists to allow more specialized catching."""
281 Exists to allow more specialized catching."""
284
282
285 detailed_exit_code = 40
283 detailed_exit_code = 40
286
284
287
285
288 class ConfigError(Abort):
286 class ConfigError(Abort):
289 """Exception raised when parsing config files"""
287 """Exception raised when parsing config files"""
290
288
291 detailed_exit_code = 30
289 detailed_exit_code = 30
292
290
293 def __init__(self, message, location=None, hint=None):
291 def __init__(self, message, location=None, hint=None):
294 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
292 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
295 super(ConfigError, self).__init__(message, hint=hint)
293 super(ConfigError, self).__init__(message, hint=hint)
296 self.location = location
294 self.location = location
297
295
298 def format(self):
296 def format(self):
299 # type: () -> bytes
297 # type: () -> bytes
300 from .i18n import _
298 from .i18n import _
301
299
302 if self.location is not None:
300 if self.location is not None:
303 message = _(b"config error at %s: %s\n") % (
301 message = _(b"config error at %s: %s\n") % (
304 pycompat.bytestr(self.location),
302 pycompat.bytestr(self.location),
305 self.message,
303 self.message,
306 )
304 )
307 else:
305 else:
308 message = _(b"config error: %s\n") % self.message
306 message = _(b"config error: %s\n") % self.message
309 if self.hint:
307 if self.hint:
310 message += _(b"(%s)\n") % self.hint
308 message += _(b"(%s)\n") % self.hint
311 return message
309 return message
312
310
313
311
314 class UpdateAbort(Abort):
312 class UpdateAbort(Abort):
315 """Raised when an update is aborted for destination issue"""
313 """Raised when an update is aborted for destination issue"""
316
314
317
315
318 class MergeDestAbort(Abort):
316 class MergeDestAbort(Abort):
319 """Raised when an update is aborted for destination issues"""
317 """Raised when an update is aborted for destination issues"""
320
318
321
319
322 class NoMergeDestAbort(MergeDestAbort):
320 class NoMergeDestAbort(MergeDestAbort):
323 """Raised when an update is aborted because there is nothing to merge"""
321 """Raised when an update is aborted because there is nothing to merge"""
324
322
325
323
326 class ManyMergeDestAbort(MergeDestAbort):
324 class ManyMergeDestAbort(MergeDestAbort):
327 """Raised when an update is aborted because destination is ambiguous"""
325 """Raised when an update is aborted because destination is ambiguous"""
328
326
329
327
330 class ResponseExpected(Abort):
328 class ResponseExpected(Abort):
331 """Raised when an EOF is received for a prompt"""
329 """Raised when an EOF is received for a prompt"""
332
330
333 def __init__(self):
331 def __init__(self):
334 from .i18n import _
332 from .i18n import _
335
333
336 Abort.__init__(self, _(b'response expected'))
334 Abort.__init__(self, _(b'response expected'))
337
335
338
336
339 class RemoteError(Abort):
337 class RemoteError(Abort):
340 """Exception raised when interacting with a remote repo fails"""
338 """Exception raised when interacting with a remote repo fails"""
341
339
342 detailed_exit_code = 100
340 detailed_exit_code = 100
343
341
344
342
345 class OutOfBandError(RemoteError):
343 class OutOfBandError(RemoteError):
346 """Exception raised when a remote repo reports failure"""
344 """Exception raised when a remote repo reports failure"""
347
345
348 def __init__(self, message=None, hint=None):
346 def __init__(self, message=None, hint=None):
349 # type: (Optional[bytes], Optional[bytes]) -> None
347 # type: (Optional[bytes], Optional[bytes]) -> None
350 from .i18n import _
348 from .i18n import _
351
349
352 if message:
350 if message:
353 # Abort.format() adds a trailing newline
351 # Abort.format() adds a trailing newline
354 message = _(b"remote error:\n%s") % message.rstrip(b'\n')
352 message = _(b"remote error:\n%s") % message.rstrip(b'\n')
355 else:
353 else:
356 message = _(b"remote error")
354 message = _(b"remote error")
357 super(OutOfBandError, self).__init__(message, hint=hint)
355 super(OutOfBandError, self).__init__(message, hint=hint)
358
356
359
357
360 class ParseError(Abort):
358 class ParseError(Abort):
361 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
359 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
362
360
363 detailed_exit_code = 10
361 detailed_exit_code = 10
364
362
365 def __init__(self, message, location=None, hint=None):
363 def __init__(self, message, location=None, hint=None):
366 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
364 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
367 super(ParseError, self).__init__(message, hint=hint)
365 super(ParseError, self).__init__(message, hint=hint)
368 self.location = location
366 self.location = location
369
367
370 def format(self):
368 def format(self):
371 # type: () -> bytes
369 # type: () -> bytes
372 from .i18n import _
370 from .i18n import _
373
371
374 if self.location is not None:
372 if self.location is not None:
375 message = _(b"hg: parse error at %s: %s\n") % (
373 message = _(b"hg: parse error at %s: %s\n") % (
376 pycompat.bytestr(self.location),
374 pycompat.bytestr(self.location),
377 self.message,
375 self.message,
378 )
376 )
379 else:
377 else:
380 message = _(b"hg: parse error: %s\n") % self.message
378 message = _(b"hg: parse error: %s\n") % self.message
381 if self.hint:
379 if self.hint:
382 message += _(b"(%s)\n") % self.hint
380 message += _(b"(%s)\n") % self.hint
383 return message
381 return message
384
382
385
383
386 class PatchError(Exception):
384 class PatchError(Exception):
387 __bytes__ = _tobytes
385 __bytes__ = _tobytes
388
386
389
387
390 class PatchParseError(PatchError):
388 class PatchParseError(PatchError):
391 __bytes__ = _tobytes
389 __bytes__ = _tobytes
392
390
393
391
394 class PatchApplicationError(PatchError):
392 class PatchApplicationError(PatchError):
395 __bytes__ = _tobytes
393 __bytes__ = _tobytes
396
394
397
395
398 def getsimilar(symbols, value):
396 def getsimilar(symbols, value):
399 # type: (Iterable[bytes], bytes) -> List[bytes]
397 # type: (Iterable[bytes], bytes) -> List[bytes]
400 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
398 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
401 # The cutoff for similarity here is pretty arbitrary. It should
399 # The cutoff for similarity here is pretty arbitrary. It should
402 # probably be investigated and tweaked.
400 # probably be investigated and tweaked.
403 return [s for s in symbols if sim(s) > 0.6]
401 return [s for s in symbols if sim(s) > 0.6]
404
402
405
403
406 def similarity_hint(similar):
404 def similarity_hint(similar):
407 # type: (List[bytes]) -> Optional[bytes]
405 # type: (List[bytes]) -> Optional[bytes]
408 from .i18n import _
406 from .i18n import _
409
407
410 if len(similar) == 1:
408 if len(similar) == 1:
411 return _(b"did you mean %s?") % similar[0]
409 return _(b"did you mean %s?") % similar[0]
412 elif similar:
410 elif similar:
413 ss = b", ".join(sorted(similar))
411 ss = b", ".join(sorted(similar))
414 return _(b"did you mean one of %s?") % ss
412 return _(b"did you mean one of %s?") % ss
415 else:
413 else:
416 return None
414 return None
417
415
418
416
419 class UnknownIdentifier(ParseError):
417 class UnknownIdentifier(ParseError):
420 """Exception raised when a {rev,file}set references an unknown identifier"""
418 """Exception raised when a {rev,file}set references an unknown identifier"""
421
419
422 def __init__(self, function, symbols):
420 def __init__(self, function, symbols):
423 # type: (bytes, Iterable[bytes]) -> None
421 # type: (bytes, Iterable[bytes]) -> None
424 from .i18n import _
422 from .i18n import _
425
423
426 similar = getsimilar(symbols, function)
424 similar = getsimilar(symbols, function)
427 hint = similarity_hint(similar)
425 hint = similarity_hint(similar)
428
426
429 ParseError.__init__(
427 ParseError.__init__(
430 self, _(b"unknown identifier: %s") % function, hint=hint
428 self, _(b"unknown identifier: %s") % function, hint=hint
431 )
429 )
432
430
433
431
434 class RepoError(Hint, Exception):
432 class RepoError(Hint, Exception):
435 __bytes__ = _tobytes
433 __bytes__ = _tobytes
436
434
437
435
438 class RepoLookupError(RepoError):
436 class RepoLookupError(RepoError):
439 pass
437 pass
440
438
441
439
442 class FilteredRepoLookupError(RepoLookupError):
440 class FilteredRepoLookupError(RepoLookupError):
443 pass
441 pass
444
442
445
443
446 class CapabilityError(RepoError):
444 class CapabilityError(RepoError):
447 pass
445 pass
448
446
449
447
450 class RequirementError(RepoError):
448 class RequirementError(RepoError):
451 """Exception raised if .hg/requires has an unknown entry."""
449 """Exception raised if .hg/requires has an unknown entry."""
452
450
453
451
454 class StdioError(IOError):
452 class StdioError(IOError):
455 """Raised if I/O to stdout or stderr fails"""
453 """Raised if I/O to stdout or stderr fails"""
456
454
457 def __init__(self, err):
455 def __init__(self, err):
458 # type: (IOError) -> None
456 # type: (IOError) -> None
459 IOError.__init__(self, err.errno, err.strerror)
457 IOError.__init__(self, err.errno, err.strerror)
460
458
461 # no __bytes__() because error message is derived from the standard IOError
459 # no __bytes__() because error message is derived from the standard IOError
462
460
463
461
464 class UnsupportedMergeRecords(Abort):
462 class UnsupportedMergeRecords(Abort):
465 def __init__(self, recordtypes):
463 def __init__(self, recordtypes):
466 # type: (Iterable[bytes]) -> None
464 # type: (Iterable[bytes]) -> None
467 from .i18n import _
465 from .i18n import _
468
466
469 self.recordtypes = sorted(recordtypes)
467 self.recordtypes = sorted(recordtypes)
470 s = b' '.join(self.recordtypes)
468 s = b' '.join(self.recordtypes)
471 Abort.__init__(
469 Abort.__init__(
472 self,
470 self,
473 _(b'unsupported merge state records: %s') % s,
471 _(b'unsupported merge state records: %s') % s,
474 hint=_(
472 hint=_(
475 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
473 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
476 b'more information'
474 b'more information'
477 ),
475 ),
478 )
476 )
479
477
480
478
481 class UnknownVersion(Abort):
479 class UnknownVersion(Abort):
482 """generic exception for aborting from an encounter with an unknown version"""
480 """generic exception for aborting from an encounter with an unknown version"""
483
481
484 def __init__(self, msg, hint=None, version=None):
482 def __init__(self, msg, hint=None, version=None):
485 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
483 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
486 self.version = version
484 self.version = version
487 super(UnknownVersion, self).__init__(msg, hint=hint)
485 super(UnknownVersion, self).__init__(msg, hint=hint)
488
486
489
487
490 class LockError(IOError):
488 class LockError(IOError):
491 def __init__(self, errno, strerror, filename, desc):
489 def __init__(self, errno, strerror, filename, desc):
492 # TODO: figure out if this should be bytes or str
490 # TODO: figure out if this should be bytes or str
493 # _type: (int, str, str, bytes) -> None
491 # _type: (int, str, str, bytes) -> None
494 IOError.__init__(self, errno, strerror, filename)
492 IOError.__init__(self, errno, strerror, filename)
495 self.desc = desc
493 self.desc = desc
496
494
497 # no __bytes__() because error message is derived from the standard IOError
495 # no __bytes__() because error message is derived from the standard IOError
498
496
499
497
500 class LockHeld(LockError):
498 class LockHeld(LockError):
501 def __init__(self, errno, filename, desc, locker):
499 def __init__(self, errno, filename, desc, locker):
502 LockError.__init__(self, errno, b'Lock held', filename, desc)
500 LockError.__init__(self, errno, b'Lock held', filename, desc)
503 self.locker = locker
501 self.locker = locker
504
502
505
503
506 class LockUnavailable(LockError):
504 class LockUnavailable(LockError):
507 pass
505 pass
508
506
509
507
510 # LockError is for errors while acquiring the lock -- this is unrelated
508 # LockError is for errors while acquiring the lock -- this is unrelated
511 class LockInheritanceContractViolation(RuntimeError):
509 class LockInheritanceContractViolation(RuntimeError):
512 __bytes__ = _tobytes
510 __bytes__ = _tobytes
513
511
514
512
515 class ResponseError(Exception):
513 class ResponseError(Exception):
516 """Raised to print an error with part of output and exit."""
514 """Raised to print an error with part of output and exit."""
517
515
518 __bytes__ = _tobytes
516 __bytes__ = _tobytes
519
517
520
518
521 # derived from KeyboardInterrupt to simplify some breakout code
519 # derived from KeyboardInterrupt to simplify some breakout code
522 class SignalInterrupt(KeyboardInterrupt):
520 class SignalInterrupt(KeyboardInterrupt):
523 """Exception raised on SIGTERM and SIGHUP."""
521 """Exception raised on SIGTERM and SIGHUP."""
524
522
525
523
526 class SignatureError(Exception):
524 class SignatureError(Exception):
527 __bytes__ = _tobytes
525 __bytes__ = _tobytes
528
526
529
527
530 class PushRaced(RuntimeError):
528 class PushRaced(RuntimeError):
531 """An exception raised during unbundling that indicate a push race"""
529 """An exception raised during unbundling that indicate a push race"""
532
530
533 __bytes__ = _tobytes
531 __bytes__ = _tobytes
534
532
535
533
536 class ProgrammingError(Hint, RuntimeError):
534 class ProgrammingError(Hint, RuntimeError):
537 """Raised if a mercurial (core or extension) developer made a mistake"""
535 """Raised if a mercurial (core or extension) developer made a mistake"""
538
536
539 def __init__(self, msg, *args, **kwargs):
537 def __init__(self, msg, *args, **kwargs):
540 # type: (AnyStr, Any, Any) -> None
538 # type: (AnyStr, Any, Any) -> None
541 # On Python 3, turn the message back into a string since this is
539 # On Python 3, turn the message back into a string since this is
542 # an internal-only error that won't be printed except in a
540 # an internal-only error that won't be printed except in a
543 # stack traces.
541 # stack traces.
544 msg = pycompat.sysstr(msg)
542 msg = pycompat.sysstr(msg)
545 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
543 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
546
544
547 __bytes__ = _tobytes
545 __bytes__ = _tobytes
548
546
549
547
550 class WdirUnsupported(Exception):
548 class WdirUnsupported(Exception):
551 """An exception which is raised when 'wdir()' is not supported"""
549 """An exception which is raised when 'wdir()' is not supported"""
552
550
553 __bytes__ = _tobytes
551 __bytes__ = _tobytes
554
552
555
553
556 # bundle2 related errors
554 # bundle2 related errors
557 class BundleValueError(ValueError):
555 class BundleValueError(ValueError):
558 """error raised when bundle2 cannot be processed"""
556 """error raised when bundle2 cannot be processed"""
559
557
560 __bytes__ = _tobytes
558 __bytes__ = _tobytes
561
559
562
560
563 class BundleUnknownFeatureError(BundleValueError):
561 class BundleUnknownFeatureError(BundleValueError):
564 def __init__(self, parttype=None, params=(), values=()):
562 def __init__(self, parttype=None, params=(), values=()):
565 self.parttype = parttype
563 self.parttype = parttype
566 self.params = params
564 self.params = params
567 self.values = values
565 self.values = values
568 if self.parttype is None:
566 if self.parttype is None:
569 msg = b'Stream Parameter'
567 msg = b'Stream Parameter'
570 else:
568 else:
571 msg = parttype
569 msg = parttype
572 entries = self.params
570 entries = self.params
573 if self.params and self.values:
571 if self.params and self.values:
574 assert len(self.params) == len(self.values)
572 assert len(self.params) == len(self.values)
575 entries = []
573 entries = []
576 for idx, par in enumerate(self.params):
574 for idx, par in enumerate(self.params):
577 val = self.values[idx]
575 val = self.values[idx]
578 if val is None:
576 if val is None:
579 entries.append(val)
577 entries.append(val)
580 else:
578 else:
581 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
579 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
582 if entries:
580 if entries:
583 msg = b'%s - %s' % (msg, b', '.join(entries))
581 msg = b'%s - %s' % (msg, b', '.join(entries))
584 ValueError.__init__(self, msg) # TODO: convert to str?
582 ValueError.__init__(self, msg) # TODO: convert to str?
585
583
586
584
587 class ReadOnlyPartError(RuntimeError):
585 class ReadOnlyPartError(RuntimeError):
588 """error raised when code tries to alter a part being generated"""
586 """error raised when code tries to alter a part being generated"""
589
587
590 __bytes__ = _tobytes
588 __bytes__ = _tobytes
591
589
592
590
593 class PushkeyFailed(Abort):
591 class PushkeyFailed(Abort):
594 """error raised when a pushkey part failed to update a value"""
592 """error raised when a pushkey part failed to update a value"""
595
593
596 def __init__(
594 def __init__(
597 self, partid, namespace=None, key=None, new=None, old=None, ret=None
595 self, partid, namespace=None, key=None, new=None, old=None, ret=None
598 ):
596 ):
599 self.partid = partid
597 self.partid = partid
600 self.namespace = namespace
598 self.namespace = namespace
601 self.key = key
599 self.key = key
602 self.new = new
600 self.new = new
603 self.old = old
601 self.old = old
604 self.ret = ret
602 self.ret = ret
605 # no i18n expected to be processed into a better message
603 # no i18n expected to be processed into a better message
606 Abort.__init__(
604 Abort.__init__(
607 self, b'failed to update value for "%s/%s"' % (namespace, key)
605 self, b'failed to update value for "%s/%s"' % (namespace, key)
608 )
606 )
609
607
610
608
611 class CensoredNodeError(StorageError):
609 class CensoredNodeError(StorageError):
612 """error raised when content verification fails on a censored node
610 """error raised when content verification fails on a censored node
613
611
614 Also contains the tombstone data substituted for the uncensored data.
612 Also contains the tombstone data substituted for the uncensored data.
615 """
613 """
616
614
617 def __init__(self, filename, node, tombstone):
615 def __init__(self, filename, node, tombstone):
618 # type: (bytes, bytes, bytes) -> None
616 # type: (bytes, bytes, bytes) -> None
619 from .node import short
617 from .node import short
620
618
621 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
619 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
622 self.tombstone = tombstone
620 self.tombstone = tombstone
623
621
624
622
625 class CensoredBaseError(StorageError):
623 class CensoredBaseError(StorageError):
626 """error raised when a delta is rejected because its base is censored
624 """error raised when a delta is rejected because its base is censored
627
625
628 A delta based on a censored revision must be formed as single patch
626 A delta based on a censored revision must be formed as single patch
629 operation which replaces the entire base with new content. This ensures
627 operation which replaces the entire base with new content. This ensures
630 the delta may be applied by clones which have not censored the base.
628 the delta may be applied by clones which have not censored the base.
631 """
629 """
632
630
633
631
634 class InvalidBundleSpecification(Exception):
632 class InvalidBundleSpecification(Exception):
635 """error raised when a bundle specification is invalid.
633 """error raised when a bundle specification is invalid.
636
634
637 This is used for syntax errors as opposed to support errors.
635 This is used for syntax errors as opposed to support errors.
638 """
636 """
639
637
640 __bytes__ = _tobytes
638 __bytes__ = _tobytes
641
639
642
640
643 class UnsupportedBundleSpecification(Exception):
641 class UnsupportedBundleSpecification(Exception):
644 """error raised when a bundle specification is not supported."""
642 """error raised when a bundle specification is not supported."""
645
643
646 __bytes__ = _tobytes
644 __bytes__ = _tobytes
647
645
648
646
649 class CorruptedState(Exception):
647 class CorruptedState(Exception):
650 """error raised when a command is not able to read its state from file"""
648 """error raised when a command is not able to read its state from file"""
651
649
652 __bytes__ = _tobytes
650 __bytes__ = _tobytes
653
651
654
652
655 class PeerTransportError(Abort):
653 class PeerTransportError(Abort):
656 """Transport-level I/O error when communicating with a peer repo."""
654 """Transport-level I/O error when communicating with a peer repo."""
657
655
658
656
659 class InMemoryMergeConflictsError(Exception):
657 class InMemoryMergeConflictsError(Exception):
660 """Exception raised when merge conflicts arose during an in-memory merge."""
658 """Exception raised when merge conflicts arose during an in-memory merge."""
661
659
662 __bytes__ = _tobytes
660 __bytes__ = _tobytes
663
661
664
662
665 class WireprotoCommandError(Exception):
663 class WireprotoCommandError(Exception):
666 """Represents an error during execution of a wire protocol command.
664 """Represents an error during execution of a wire protocol command.
667
665
668 Should only be thrown by wire protocol version 2 commands.
666 Should only be thrown by wire protocol version 2 commands.
669
667
670 The error is a formatter string and an optional iterable of arguments.
668 The error is a formatter string and an optional iterable of arguments.
671 """
669 """
672
670
673 def __init__(self, message, args=None):
671 def __init__(self, message, args=None):
674 # type: (bytes, Optional[Sequence[bytes]]) -> None
672 # type: (bytes, Optional[Sequence[bytes]]) -> None
675 self.message = message
673 self.message = message
676 self.messageargs = args
674 self.messageargs = args
General Comments 0
You need to be logged in to leave comments. Login now