Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/error.py @ 51304:f15cb5111a1e
pytype: move some type comment to proper annotation
We support direct type annotations now, while pytype is starting to complains
about them.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Tue, 19 Dec 2023 21:29:34 +0100 |
parents | 81224afd938d |
children | 8b2ea2246a5f |
comparison
equal
deleted
inserted
replaced
51303:81224afd938d | 51304:f15cb5111a1e |
---|---|
38 Sequence, | 38 Sequence, |
39 Union, | 39 Union, |
40 ] | 40 ] |
41 | 41 |
42 | 42 |
43 def _tobytes(exc): | 43 def _tobytes(exc) -> bytes: |
44 # type: (...) -> bytes | |
45 """Byte-stringify exception in the same way as BaseException_str()""" | 44 """Byte-stringify exception in the same way as BaseException_str()""" |
46 if not exc.args: | 45 if not exc.args: |
47 return b'' | 46 return b'' |
48 if len(exc.args) == 1: | 47 if len(exc.args) == 1: |
49 return pycompat.bytestr(exc.args[0]) | 48 return pycompat.bytestr(exc.args[0]) |
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 |
214 """Exception raised when a command requires human intervention.""" | 208 """Exception raised when a command requires human intervention.""" |
215 | 209 |
216 coarse_exit_code = 1 | 210 coarse_exit_code = 1 |
217 detailed_exit_code = 240 | 211 detailed_exit_code = 240 |
218 | 212 |
219 def format(self): | 213 def format(self) -> bytes: |
220 # type: () -> bytes | |
221 from .i18n import _ | 214 from .i18n import _ |
222 | 215 |
223 message = _(b"%s\n") % self.message | 216 message = _(b"%s\n") % self.message |
224 if self.hint: | 217 if self.hint: |
225 message += _(b"(%s)\n") % self.hint | 218 message += _(b"(%s)\n") % self.hint |
227 | 220 |
228 | 221 |
229 class ConflictResolutionRequired(InterventionRequired): | 222 class ConflictResolutionRequired(InterventionRequired): |
230 """Exception raised when a continuable command required merge conflict resolution.""" | 223 """Exception raised when a continuable command required merge conflict resolution.""" |
231 | 224 |
232 def __init__(self, opname): | 225 def __init__(self, opname: bytes) -> None: |
233 # type: (bytes) -> None | |
234 from .i18n import _ | 226 from .i18n import _ |
235 | 227 |
236 self.opname = opname | 228 self.opname = opname |
237 InterventionRequired.__init__( | 229 InterventionRequired.__init__( |
238 self, | 230 self, |
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 |