Mercurial > public > mercurial-scm > hg
comparison mercurial/error.py @ 47304:73f52278a158
errors: make exit codes class variables instead
Kyle pointed out to me that we can simply make the exit codes class
variables. Python provides some magic for making them accessible as
instance variables.
This also makes it easier to let subclasses of existing errors
override the exit codes by letting them simply define their own values
as class variables. That means that there's no need to pass them into
the superclass's constructor arguments, so the superclass doesn't need
to expose the them as arguments. (Making a subclass set a different
exit code for a subclass of `StorageError` was actually the goal with
my recent series.)
Differential Revision: https://phab.mercurial-scm.org/D10758
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Thu, 20 May 2021 08:15:57 -0700 |
parents | dd339191f2dc |
children | 9de0823705b4 |
comparison
equal
deleted
inserted
replaced
47303:e4ccc341e65b | 47304:73f52278a158 |
---|---|
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 def __init__( | 57 coarse_exit_code = None |
58 self, message, hint=None, coarse_exit_code=None, detailed_exit_code=None | 58 detailed_exit_code = None |
59 ): | 59 |
60 def __init__(self, message, hint=None): | |
60 # type: (bytes, Optional[bytes]) -> None | 61 # type: (bytes, Optional[bytes]) -> None |
61 self.message = message | 62 self.message = message |
62 self.hint = hint | 63 self.hint = hint |
63 self.coarse_exit_code = coarse_exit_code | |
64 self.detailed_exit_code = detailed_exit_code | |
65 # Pass the message into the Exception constructor to help extensions | 64 # Pass the message into the Exception constructor to help extensions |
66 # that look for exc.args[0]. | 65 # that look for exc.args[0]. |
67 Exception.__init__(self, message) | 66 Exception.__init__(self, message) |
68 | 67 |
69 def __bytes__(self): | 68 def __bytes__(self): |
95 """Raised when an error occurs in a storage layer. | 94 """Raised when an error occurs in a storage layer. |
96 | 95 |
97 Usually subclassed by a storage-specific exception. | 96 Usually subclassed by a storage-specific exception. |
98 """ | 97 """ |
99 | 98 |
100 def __init__(self, message, hint=None): | 99 detailed_exit_code = 50 |
101 super(StorageError, self).__init__( | |
102 message, hint=hint, detailed_exit_code=50 | |
103 ) | |
104 | 100 |
105 | 101 |
106 class RevlogError(StorageError): | 102 class RevlogError(StorageError): |
107 pass | 103 pass |
108 | 104 |
203 | 199 |
204 | 200 |
205 class InterventionRequired(Abort): | 201 class InterventionRequired(Abort): |
206 """Exception raised when a command requires human intervention.""" | 202 """Exception raised when a command requires human intervention.""" |
207 | 203 |
208 def __init__(self, message, hint=None): | 204 coarse_exit_code = 1 |
209 super(InterventionRequired, self).__init__( | 205 detailed_exit_code = 240 |
210 message, hint=hint, coarse_exit_code=1, detailed_exit_code=240 | |
211 ) | |
212 | 206 |
213 def format(self): | 207 def format(self): |
214 # type: () -> bytes | 208 # type: () -> bytes |
215 from .i18n import _ | 209 from .i18n import _ |
216 | 210 |
241 """Indicates that the user made an error in their input. | 235 """Indicates that the user made an error in their input. |
242 | 236 |
243 Examples: Invalid command, invalid flags, invalid revision. | 237 Examples: Invalid command, invalid flags, invalid revision. |
244 """ | 238 """ |
245 | 239 |
246 def __init__(self, message, hint=None): | 240 detailed_exit_code = 10 |
247 super(InputError, self).__init__( | |
248 message, hint=hint, detailed_exit_code=10 | |
249 ) | |
250 | 241 |
251 | 242 |
252 class StateError(Abort): | 243 class StateError(Abort): |
253 """Indicates that the operation might work if retried in a different state. | 244 """Indicates that the operation might work if retried in a different state. |
254 | 245 |
255 Examples: Unresolved merge conflicts, unfinished operations. | 246 Examples: Unresolved merge conflicts, unfinished operations. |
256 """ | 247 """ |
257 | 248 |
258 def __init__(self, message, hint=None): | 249 detailed_exit_code = 20 |
259 super(StateError, self).__init__( | |
260 message, hint=hint, detailed_exit_code=20 | |
261 ) | |
262 | 250 |
263 | 251 |
264 class CanceledError(Abort): | 252 class CanceledError(Abort): |
265 """Indicates that the user canceled the operation. | 253 """Indicates that the user canceled the operation. |
266 | 254 |
267 Examples: Close commit editor with error status, quit chistedit. | 255 Examples: Close commit editor with error status, quit chistedit. |
268 """ | 256 """ |
269 | 257 |
270 def __init__(self, message, hint=None): | 258 detailed_exit_code = 250 |
271 super(CanceledError, self).__init__( | |
272 message, hint=hint, detailed_exit_code=250 | |
273 ) | |
274 | 259 |
275 | 260 |
276 class SecurityError(Abort): | 261 class SecurityError(Abort): |
277 """Indicates that some aspect of security failed. | 262 """Indicates that some aspect of security failed. |
278 | 263 |
279 Examples: Bad server credentials, expired local credentials for network | 264 Examples: Bad server credentials, expired local credentials for network |
280 filesystem, mismatched GPG signature, DoS protection. | 265 filesystem, mismatched GPG signature, DoS protection. |
281 """ | 266 """ |
282 | 267 |
283 def __init__(self, message, hint=None): | 268 detailed_exit_code = 150 |
284 super(SecurityError, self).__init__( | |
285 message, hint=hint, detailed_exit_code=150 | |
286 ) | |
287 | 269 |
288 | 270 |
289 class HookLoadError(Abort): | 271 class HookLoadError(Abort): |
290 """raised when loading a hook fails, aborting an operation | 272 """raised when loading a hook fails, aborting an operation |
291 | 273 |
295 class HookAbort(Abort): | 277 class HookAbort(Abort): |
296 """raised when a validation hook fails, aborting an operation | 278 """raised when a validation hook fails, aborting an operation |
297 | 279 |
298 Exists to allow more specialized catching.""" | 280 Exists to allow more specialized catching.""" |
299 | 281 |
300 def __init__(self, message, hint=None): | 282 detailed_exit_code = 40 |
301 super(HookAbort, self).__init__( | |
302 message, hint=hint, detailed_exit_code=40 | |
303 ) | |
304 | 283 |
305 | 284 |
306 class ConfigError(Abort): | 285 class ConfigError(Abort): |
307 """Exception raised when parsing config files""" | 286 """Exception raised when parsing config files""" |
308 | 287 |
288 detailed_exit_code = 30 | |
289 | |
309 def __init__(self, message, location=None, hint=None): | 290 def __init__(self, message, location=None, hint=None): |
310 # type: (bytes, Optional[bytes], Optional[bytes]) -> None | 291 # type: (bytes, Optional[bytes], Optional[bytes]) -> None |
311 super(ConfigError, self).__init__( | 292 super(ConfigError, self).__init__(message, hint=hint) |
312 message, hint=hint, detailed_exit_code=30 | |
313 ) | |
314 self.location = location | 293 self.location = location |
315 | 294 |
316 def format(self): | 295 def format(self): |
317 # type: () -> bytes | 296 # type: () -> bytes |
318 from .i18n import _ | 297 from .i18n import _ |
355 | 334 |
356 | 335 |
357 class RemoteError(Abort): | 336 class RemoteError(Abort): |
358 """Exception raised when interacting with a remote repo fails""" | 337 """Exception raised when interacting with a remote repo fails""" |
359 | 338 |
360 def __init__(self, message, hint=None): | 339 detailed_exit_code = 100 |
361 super(RemoteError, self).__init__( | |
362 message, hint=hint, detailed_exit_code=100 | |
363 ) | |
364 | 340 |
365 | 341 |
366 class OutOfBandError(RemoteError): | 342 class OutOfBandError(RemoteError): |
367 """Exception raised when a remote repo reports failure""" | 343 """Exception raised when a remote repo reports failure""" |
368 | 344 |
378 | 354 |
379 | 355 |
380 class ParseError(Abort): | 356 class ParseError(Abort): |
381 """Raised when parsing config files and {rev,file}sets (msg[, pos])""" | 357 """Raised when parsing config files and {rev,file}sets (msg[, pos])""" |
382 | 358 |
359 detailed_exit_code = 10 | |
360 | |
383 def __init__(self, message, location=None, hint=None): | 361 def __init__(self, message, location=None, hint=None): |
384 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None | 362 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None |
385 super(ParseError, self).__init__( | 363 super(ParseError, self).__init__(message, hint=hint) |
386 message, hint=hint, detailed_exit_code=10 | |
387 ) | |
388 self.location = location | 364 self.location = location |
389 | 365 |
390 def format(self): | 366 def format(self): |
391 # type: () -> bytes | 367 # type: () -> bytes |
392 from .i18n import _ | 368 from .i18n import _ |