66 """Base class for Mercurial errors.""" |
65 """Base class for Mercurial errors.""" |
67 |
66 |
68 coarse_exit_code = None |
67 coarse_exit_code = None |
69 detailed_exit_code = None |
68 detailed_exit_code = None |
70 |
69 |
71 def __init__(self, message, hint=None): |
70 def __init__(self, message: bytes, hint: Optional[bytes] = None) -> None: |
72 # type: (bytes, Optional[bytes]) -> None |
|
73 self.message = message |
71 self.message = message |
74 self.hint = hint |
72 self.hint = hint |
75 # Pass the message into the Exception constructor to help extensions |
73 # Pass the message into the Exception constructor to help extensions |
76 # that look for exc.args[0]. |
74 # that look for exc.args[0]. |
77 Exception.__init__(self, message) |
75 Exception.__init__(self, message) |
78 |
76 |
79 def __bytes__(self): |
77 def __bytes__(self): |
80 return self.message |
78 return self.message |
81 |
79 |
82 def __str__(self): |
80 def __str__(self) -> str: |
83 # type: () -> str |
|
84 # the output would be unreadable if the message was translated, |
81 # the output would be unreadable if the message was translated, |
85 # but do not replace it with encoding.strfromlocal(), which |
82 # but do not replace it with encoding.strfromlocal(), which |
86 # may raise another exception. |
83 # may raise another exception. |
87 return pycompat.sysstr(self.__bytes__()) |
84 return pycompat.sysstr(self.__bytes__()) |
88 |
85 |
89 def format(self): |
86 def format(self) -> bytes: |
90 # type: () -> bytes |
|
91 from .i18n import _ |
87 from .i18n import _ |
92 |
88 |
93 message = _(b"abort: %s\n") % self.message |
89 message = _(b"abort: %s\n") % self.message |
94 if self.hint: |
90 if self.hint: |
95 message += _(b"(%s)\n") % self.hint |
91 message += _(b"(%s)\n") % self.hint |
112 class RevlogError(StorageError): |
108 class RevlogError(StorageError): |
113 pass |
109 pass |
114 |
110 |
115 |
111 |
116 class SidedataHashError(RevlogError): |
112 class SidedataHashError(RevlogError): |
117 def __init__(self, key, expected, got): |
113 def __init__(self, key: int, expected: bytes, got: bytes) -> None: |
118 # type: (int, bytes, bytes) -> None |
|
119 self.hint = None |
114 self.hint = None |
120 self.sidedatakey = key |
115 self.sidedatakey = key |
121 self.expecteddigest = expected |
116 self.expecteddigest = expected |
122 self.actualdigest = got |
117 self.actualdigest = got |
123 |
118 |
125 class FilteredIndexError(IndexError): |
120 class FilteredIndexError(IndexError): |
126 __bytes__ = _tobytes |
121 __bytes__ = _tobytes |
127 |
122 |
128 |
123 |
129 class LookupError(RevlogError, KeyError): |
124 class LookupError(RevlogError, KeyError): |
130 def __init__(self, name, index, message): |
125 def __init__(self, name: bytes, index: bytes, message: bytes) -> None: |
131 # type: (bytes, bytes, bytes) -> None |
|
132 self.name = name |
126 self.name = name |
133 self.index = index |
127 self.index = index |
134 # this can't be called 'message' because at least some installs of |
128 # this can't be called 'message' because at least some installs of |
135 # Python 2.6+ complain about the 'message' property being deprecated |
129 # Python 2.6+ complain about the 'message' property being deprecated |
136 self.lookupmessage = message |
130 self.lookupmessage = message |
163 |
157 |
164 |
158 |
165 class CommandError(Exception): |
159 class CommandError(Exception): |
166 """Exception raised on errors in parsing the command line.""" |
160 """Exception raised on errors in parsing the command line.""" |
167 |
161 |
168 def __init__(self, command, message): |
162 def __init__(self, command: Optional[bytes], message: bytes) -> None: |
169 # type: (Optional[bytes], bytes) -> None |
|
170 self.command = command |
163 self.command = command |
171 self.message = message |
164 self.message = message |
172 super(CommandError, self).__init__() |
165 super(CommandError, self).__init__() |
173 |
166 |
174 __bytes__ = _tobytes |
167 __bytes__ = _tobytes |
175 |
168 |
176 |
169 |
177 class UnknownCommand(Exception): |
170 class UnknownCommand(Exception): |
178 """Exception raised if command is not in the command table.""" |
171 """Exception raised if command is not in the command table.""" |
179 |
172 |
180 def __init__(self, command, all_commands=None): |
173 def __init__( |
181 # type: (bytes, Optional[List[bytes]]) -> None |
174 self, |
|
175 command: bytes, |
|
176 all_commands: Optional[List[bytes]] = None, |
|
177 ) -> None: |
182 self.command = command |
178 self.command = command |
183 self.all_commands = all_commands |
179 self.all_commands = all_commands |
184 super(UnknownCommand, self).__init__() |
180 super(UnknownCommand, self).__init__() |
185 |
181 |
186 __bytes__ = _tobytes |
182 __bytes__ = _tobytes |
187 |
183 |
188 |
184 |
189 class AmbiguousCommand(Exception): |
185 class AmbiguousCommand(Exception): |
190 """Exception raised if command shortcut matches more than one command.""" |
186 """Exception raised if command shortcut matches more than one command.""" |
191 |
187 |
192 def __init__(self, prefix, matches): |
188 def __init__(self, prefix: bytes, matches: List[bytes]) -> None: |
193 # type: (bytes, List[bytes]) -> None |
|
194 self.prefix = prefix |
189 self.prefix = prefix |
195 self.matches = matches |
190 self.matches = matches |
196 super(AmbiguousCommand, self).__init__() |
191 super(AmbiguousCommand, self).__init__() |
197 |
192 |
198 __bytes__ = _tobytes |
193 __bytes__ = _tobytes |
199 |
194 |
200 |
195 |
201 class WorkerError(Exception): |
196 class WorkerError(Exception): |
202 """Exception raised when a worker process dies.""" |
197 """Exception raised when a worker process dies.""" |
203 |
198 |
204 def __init__(self, status_code): |
199 def __init__(self, status_code: int) -> None: |
205 # type: (int) -> None |
|
206 self.status_code = status_code |
200 self.status_code = status_code |
207 # Pass status code to superclass just so it becomes part of __bytes__ |
201 # Pass status code to superclass just so it becomes part of __bytes__ |
208 super(WorkerError, self).__init__(status_code) |
202 super(WorkerError, self).__init__(status_code) |
209 |
203 |
210 __bytes__ = _tobytes |
204 __bytes__ = _tobytes |
297 class ConfigError(Abort): |
289 class ConfigError(Abort): |
298 """Exception raised when parsing config files""" |
290 """Exception raised when parsing config files""" |
299 |
291 |
300 detailed_exit_code = 30 |
292 detailed_exit_code = 30 |
301 |
293 |
302 def __init__(self, message, location=None, hint=None): |
294 def __init__( |
303 # type: (bytes, Optional[bytes], Optional[bytes]) -> None |
295 self, |
|
296 message: bytes, |
|
297 location: Optional[bytes] = None, |
|
298 hint: Optional[bytes] = None, |
|
299 ) -> None: |
304 super(ConfigError, self).__init__(message, hint=hint) |
300 super(ConfigError, self).__init__(message, hint=hint) |
305 self.location = location |
301 self.location = location |
306 |
302 |
307 def format(self): |
303 def format(self) -> bytes: |
308 # type: () -> bytes |
|
309 from .i18n import _ |
304 from .i18n import _ |
310 |
305 |
311 if self.location is not None: |
306 if self.location is not None: |
312 message = _(b"config error at %s: %s\n") % ( |
307 message = _(b"config error at %s: %s\n") % ( |
313 pycompat.bytestr(self.location), |
308 pycompat.bytestr(self.location), |
352 |
347 |
353 |
348 |
354 class OutOfBandError(RemoteError): |
349 class OutOfBandError(RemoteError): |
355 """Exception raised when a remote repo reports failure""" |
350 """Exception raised when a remote repo reports failure""" |
356 |
351 |
357 def __init__(self, message=None, hint=None): |
352 def __init__( |
358 # type: (Optional[bytes], Optional[bytes]) -> None |
353 self, |
|
354 message: Optional[bytes] = None, |
|
355 hint: Optional[bytes] = None, |
|
356 ): |
359 from .i18n import _ |
357 from .i18n import _ |
360 |
358 |
361 if message: |
359 if message: |
362 # Abort.format() adds a trailing newline |
360 # Abort.format() adds a trailing newline |
363 message = _(b"remote error:\n%s") % message.rstrip(b'\n') |
361 message = _(b"remote error:\n%s") % message.rstrip(b'\n') |
369 class ParseError(Abort): |
367 class ParseError(Abort): |
370 """Raised when parsing config files and {rev,file}sets (msg[, pos])""" |
368 """Raised when parsing config files and {rev,file}sets (msg[, pos])""" |
371 |
369 |
372 detailed_exit_code = 10 |
370 detailed_exit_code = 10 |
373 |
371 |
374 def __init__(self, message, location=None, hint=None): |
372 def __init__( |
375 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None |
373 self, |
|
374 message: bytes, |
|
375 location: Optional[Union[bytes, int]] = None, |
|
376 hint: Optional[bytes] = None, |
|
377 ): |
376 super(ParseError, self).__init__(message, hint=hint) |
378 super(ParseError, self).__init__(message, hint=hint) |
377 self.location = location |
379 self.location = location |
378 |
380 |
379 def format(self): |
381 def format(self) -> bytes: |
380 # type: () -> bytes |
|
381 from .i18n import _ |
382 from .i18n import _ |
382 |
383 |
383 if self.location is not None: |
384 if self.location is not None: |
384 message = _(b"hg: parse error at %s: %s\n") % ( |
385 message = _(b"hg: parse error at %s: %s\n") % ( |
385 pycompat.bytestr(self.location), |
386 pycompat.bytestr(self.location), |
402 |
403 |
403 class PatchApplicationError(PatchError): |
404 class PatchApplicationError(PatchError): |
404 __bytes__ = _tobytes |
405 __bytes__ = _tobytes |
405 |
406 |
406 |
407 |
407 def getsimilar(symbols, value): |
408 def getsimilar(symbols: Iterable[bytes], value: bytes) -> List[bytes]: |
408 # type: (Iterable[bytes], bytes) -> List[bytes] |
|
409 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio() |
409 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio() |
410 # The cutoff for similarity here is pretty arbitrary. It should |
410 # The cutoff for similarity here is pretty arbitrary. It should |
411 # probably be investigated and tweaked. |
411 # probably be investigated and tweaked. |
412 return [s for s in symbols if sim(s) > 0.6] |
412 return [s for s in symbols if sim(s) > 0.6] |
413 |
413 |
414 |
414 |
415 def similarity_hint(similar): |
415 def similarity_hint(similar: List[bytes]) -> Optional[bytes]: |
416 # type: (List[bytes]) -> Optional[bytes] |
|
417 from .i18n import _ |
416 from .i18n import _ |
418 |
417 |
419 if len(similar) == 1: |
418 if len(similar) == 1: |
420 return _(b"did you mean %s?") % similar[0] |
419 return _(b"did you mean %s?") % similar[0] |
421 elif similar: |
420 elif similar: |
426 |
425 |
427 |
426 |
428 class UnknownIdentifier(ParseError): |
427 class UnknownIdentifier(ParseError): |
429 """Exception raised when a {rev,file}set references an unknown identifier""" |
428 """Exception raised when a {rev,file}set references an unknown identifier""" |
430 |
429 |
431 def __init__(self, function, symbols): |
430 def __init__(self, function: bytes, symbols: Iterable[bytes]) -> None: |
432 # type: (bytes, Iterable[bytes]) -> None |
|
433 from .i18n import _ |
431 from .i18n import _ |
434 |
432 |
435 similar = getsimilar(symbols, function) |
433 similar = getsimilar(symbols, function) |
436 hint = similarity_hint(similar) |
434 hint = similarity_hint(similar) |
437 |
435 |
461 |
459 |
462 |
460 |
463 class StdioError(IOError): |
461 class StdioError(IOError): |
464 """Raised if I/O to stdout or stderr fails""" |
462 """Raised if I/O to stdout or stderr fails""" |
465 |
463 |
466 def __init__(self, err): |
464 def __init__(self, err: IOError) -> None: |
467 # type: (IOError) -> None |
|
468 IOError.__init__(self, err.errno, err.strerror) |
465 IOError.__init__(self, err.errno, err.strerror) |
469 |
466 |
470 # no __bytes__() because error message is derived from the standard IOError |
467 # no __bytes__() because error message is derived from the standard IOError |
471 |
468 |
472 |
469 |
473 class UnsupportedMergeRecords(Abort): |
470 class UnsupportedMergeRecords(Abort): |
474 def __init__(self, recordtypes): |
471 def __init__(self, recordtypes: Iterable[bytes]) -> None: |
475 # type: (Iterable[bytes]) -> None |
|
476 from .i18n import _ |
472 from .i18n import _ |
477 |
473 |
478 self.recordtypes = sorted(recordtypes) |
474 self.recordtypes = sorted(recordtypes) |
479 s = b' '.join(self.recordtypes) |
475 s = b' '.join(self.recordtypes) |
480 Abort.__init__( |
476 Abort.__init__( |
488 |
484 |
489 |
485 |
490 class UnknownVersion(Abort): |
486 class UnknownVersion(Abort): |
491 """generic exception for aborting from an encounter with an unknown version""" |
487 """generic exception for aborting from an encounter with an unknown version""" |
492 |
488 |
493 def __init__(self, msg, hint=None, version=None): |
489 def __init__( |
494 # type: (bytes, Optional[bytes], Optional[bytes]) -> None |
490 self, |
|
491 msg: bytes, |
|
492 hint: Optional[bytes] = None, |
|
493 version: Optional[bytes] = None, |
|
494 ) -> None: |
495 self.version = version |
495 self.version = version |
496 super(UnknownVersion, self).__init__(msg, hint=hint) |
496 super(UnknownVersion, self).__init__(msg, hint=hint) |
497 |
497 |
498 |
498 |
499 class LockError(IOError): |
499 class LockError(IOError): |
500 def __init__(self, errno, strerror, filename, desc): |
500 def __init__( |
501 # _type: (int, str, bytes, bytes) -> None |
501 self, |
|
502 errno: int, |
|
503 strerror: str, |
|
504 filename: bytes, |
|
505 desc: Optional[bytes], |
|
506 ) -> None: |
502 IOError.__init__(self, errno, strerror, filename) |
507 IOError.__init__(self, errno, strerror, filename) |
503 self.desc = desc |
508 self.desc = desc |
504 |
509 |
505 # no __bytes__() because error message is derived from the standard IOError |
510 # no __bytes__() because error message is derived from the standard IOError |
506 |
511 |
507 |
512 |
508 class LockHeld(LockError): |
513 class LockHeld(LockError): |
509 def __init__(self, errno, filename, desc, locker): |
514 def __init__( |
|
515 self, |
|
516 errno: int, |
|
517 filename: bytes, |
|
518 desc: Optional[bytes], |
|
519 locker, |
|
520 ): |
510 LockError.__init__(self, errno, 'Lock held', filename, desc) |
521 LockError.__init__(self, errno, 'Lock held', filename, desc) |
|
522 self.filename: bytes = filename |
511 self.locker = locker |
523 self.locker = locker |
512 |
524 |
513 |
525 |
514 class LockUnavailable(LockError): |
526 class LockUnavailable(LockError): |
515 pass |
527 pass |
542 |
554 |
543 |
555 |
544 class ProgrammingError(Hint, RuntimeError): |
556 class ProgrammingError(Hint, RuntimeError): |
545 """Raised if a mercurial (core or extension) developer made a mistake""" |
557 """Raised if a mercurial (core or extension) developer made a mistake""" |
546 |
558 |
547 def __init__(self, msg, *args, **kwargs): |
559 def __init__(self, msg: AnyStr, *args, **kwargs): |
548 # type: (AnyStr, Any, Any) -> None |
|
549 # On Python 3, turn the message back into a string since this is |
560 # On Python 3, turn the message back into a string since this is |
550 # an internal-only error that won't be printed except in a |
561 # an internal-only error that won't be printed except in a |
551 # stack traces. |
562 # stack traces. |
552 msg = pycompat.sysstr(msg) |
563 msg = pycompat.sysstr(msg) |
553 super(ProgrammingError, self).__init__(msg, *args, **kwargs) |
564 super(ProgrammingError, self).__init__(msg, *args, **kwargs) |
620 """error raised when content verification fails on a censored node |
631 """error raised when content verification fails on a censored node |
621 |
632 |
622 Also contains the tombstone data substituted for the uncensored data. |
633 Also contains the tombstone data substituted for the uncensored data. |
623 """ |
634 """ |
624 |
635 |
625 def __init__(self, filename, node, tombstone): |
636 def __init__(self, filename: bytes, node: bytes, tombstone: bytes): |
626 # type: (bytes, bytes, bytes) -> None |
|
627 from .node import short |
637 from .node import short |
628 |
638 |
629 StorageError.__init__(self, b'%s:%s' % (filename, short(node))) |
639 StorageError.__init__(self, b'%s:%s' % (filename, short(node))) |
630 self.tombstone = tombstone |
640 self.tombstone = tombstone |
631 |
641 |
683 Should only be thrown by wire protocol version 2 commands. |
693 Should only be thrown by wire protocol version 2 commands. |
684 |
694 |
685 The error is a formatter string and an optional iterable of arguments. |
695 The error is a formatter string and an optional iterable of arguments. |
686 """ |
696 """ |
687 |
697 |
688 def __init__(self, message, args=None): |
698 def __init__( |
689 # type: (bytes, Optional[Sequence[bytes]]) -> None |
699 self, |
|
700 message: bytes, |
|
701 args: Optional[Sequence[bytes]] = None, |
|
702 ) -> None: |
690 self.message = message |
703 self.message = message |
691 self.messageargs = args |
704 self.messageargs = args |