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 _