##// END OF EJS Templates
py3: use sysstr() to convert ProgrammingError bytes with no unicode error risk...
Yuya Nishihara -
r39632:409c42d6 default
parent child Browse files
Show More
@@ -1,331 +1,329
1 # error.py - Mercurial exceptions
1 # error.py - Mercurial exceptions
2 #
2 #
3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2008 Matt Mackall <mpm@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 from __future__ import absolute_import
14 from __future__ import absolute_import
15
15
16 # Do not import anything but pycompat here, please
16 # Do not import anything but pycompat here, please
17 from . import pycompat
17 from . import pycompat
18
18
19 def _tobytes(exc):
19 def _tobytes(exc):
20 """Byte-stringify exception in the same way as BaseException_str()"""
20 """Byte-stringify exception in the same way as BaseException_str()"""
21 if not exc.args:
21 if not exc.args:
22 return b''
22 return b''
23 if len(exc.args) == 1:
23 if len(exc.args) == 1:
24 return pycompat.bytestr(exc.args[0])
24 return pycompat.bytestr(exc.args[0])
25 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
25 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
26
26
27 class Hint(object):
27 class Hint(object):
28 """Mix-in to provide a hint of an error
28 """Mix-in to provide a hint of an error
29
29
30 This should come first in the inheritance list to consume a hint and
30 This should come first in the inheritance list to consume a hint and
31 pass remaining arguments to the exception class.
31 pass remaining arguments to the exception class.
32 """
32 """
33 def __init__(self, *args, **kw):
33 def __init__(self, *args, **kw):
34 self.hint = kw.pop(r'hint', None)
34 self.hint = kw.pop(r'hint', None)
35 super(Hint, self).__init__(*args, **kw)
35 super(Hint, self).__init__(*args, **kw)
36
36
37 class RevlogError(Hint, Exception):
37 class RevlogError(Hint, Exception):
38 __bytes__ = _tobytes
38 __bytes__ = _tobytes
39
39
40 class FilteredIndexError(IndexError):
40 class FilteredIndexError(IndexError):
41 __bytes__ = _tobytes
41 __bytes__ = _tobytes
42
42
43 class LookupError(RevlogError, KeyError):
43 class LookupError(RevlogError, KeyError):
44 def __init__(self, name, index, message):
44 def __init__(self, name, index, message):
45 self.name = name
45 self.name = name
46 self.index = index
46 self.index = index
47 # this can't be called 'message' because at least some installs of
47 # this can't be called 'message' because at least some installs of
48 # Python 2.6+ complain about the 'message' property being deprecated
48 # Python 2.6+ complain about the 'message' property being deprecated
49 self.lookupmessage = message
49 self.lookupmessage = message
50 if isinstance(name, bytes) and len(name) == 20:
50 if isinstance(name, bytes) and len(name) == 20:
51 from .node import short
51 from .node import short
52 name = short(name)
52 name = short(name)
53 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
53 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
54
54
55 def __bytes__(self):
55 def __bytes__(self):
56 return RevlogError.__bytes__(self)
56 return RevlogError.__bytes__(self)
57
57
58 def __str__(self):
58 def __str__(self):
59 return RevlogError.__str__(self)
59 return RevlogError.__str__(self)
60
60
61 class AmbiguousPrefixLookupError(LookupError):
61 class AmbiguousPrefixLookupError(LookupError):
62 pass
62 pass
63
63
64 class FilteredLookupError(LookupError):
64 class FilteredLookupError(LookupError):
65 pass
65 pass
66
66
67 class ManifestLookupError(LookupError):
67 class ManifestLookupError(LookupError):
68 pass
68 pass
69
69
70 class CommandError(Exception):
70 class CommandError(Exception):
71 """Exception raised on errors in parsing the command line."""
71 """Exception raised on errors in parsing the command line."""
72 __bytes__ = _tobytes
72 __bytes__ = _tobytes
73
73
74 class InterventionRequired(Hint, Exception):
74 class InterventionRequired(Hint, Exception):
75 """Exception raised when a command requires human intervention."""
75 """Exception raised when a command requires human intervention."""
76 __bytes__ = _tobytes
76 __bytes__ = _tobytes
77
77
78 class Abort(Hint, Exception):
78 class Abort(Hint, Exception):
79 """Raised if a command needs to print an error and exit."""
79 """Raised if a command needs to print an error and exit."""
80 __bytes__ = _tobytes
80 __bytes__ = _tobytes
81
81
82 class HookLoadError(Abort):
82 class HookLoadError(Abort):
83 """raised when loading a hook fails, aborting an operation
83 """raised when loading a hook fails, aborting an operation
84
84
85 Exists to allow more specialized catching."""
85 Exists to allow more specialized catching."""
86
86
87 class HookAbort(Abort):
87 class HookAbort(Abort):
88 """raised when a validation hook fails, aborting an operation
88 """raised when a validation hook fails, aborting an operation
89
89
90 Exists to allow more specialized catching."""
90 Exists to allow more specialized catching."""
91
91
92 class ConfigError(Abort):
92 class ConfigError(Abort):
93 """Exception raised when parsing config files"""
93 """Exception raised when parsing config files"""
94
94
95 class UpdateAbort(Abort):
95 class UpdateAbort(Abort):
96 """Raised when an update is aborted for destination issue"""
96 """Raised when an update is aborted for destination issue"""
97
97
98 class MergeDestAbort(Abort):
98 class MergeDestAbort(Abort):
99 """Raised when an update is aborted for destination issues"""
99 """Raised when an update is aborted for destination issues"""
100
100
101 class NoMergeDestAbort(MergeDestAbort):
101 class NoMergeDestAbort(MergeDestAbort):
102 """Raised when an update is aborted because there is nothing to merge"""
102 """Raised when an update is aborted because there is nothing to merge"""
103
103
104 class ManyMergeDestAbort(MergeDestAbort):
104 class ManyMergeDestAbort(MergeDestAbort):
105 """Raised when an update is aborted because destination is ambiguous"""
105 """Raised when an update is aborted because destination is ambiguous"""
106
106
107 class ResponseExpected(Abort):
107 class ResponseExpected(Abort):
108 """Raised when an EOF is received for a prompt"""
108 """Raised when an EOF is received for a prompt"""
109 def __init__(self):
109 def __init__(self):
110 from .i18n import _
110 from .i18n import _
111 Abort.__init__(self, _('response expected'))
111 Abort.__init__(self, _('response expected'))
112
112
113 class OutOfBandError(Hint, Exception):
113 class OutOfBandError(Hint, Exception):
114 """Exception raised when a remote repo reports failure"""
114 """Exception raised when a remote repo reports failure"""
115 __bytes__ = _tobytes
115 __bytes__ = _tobytes
116
116
117 class ParseError(Hint, Exception):
117 class ParseError(Hint, Exception):
118 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
118 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
119 __bytes__ = _tobytes
119 __bytes__ = _tobytes
120
120
121 class PatchError(Exception):
121 class PatchError(Exception):
122 __bytes__ = _tobytes
122 __bytes__ = _tobytes
123
123
124 class UnknownIdentifier(ParseError):
124 class UnknownIdentifier(ParseError):
125 """Exception raised when a {rev,file}set references an unknown identifier"""
125 """Exception raised when a {rev,file}set references an unknown identifier"""
126
126
127 def __init__(self, function, symbols):
127 def __init__(self, function, symbols):
128 from .i18n import _
128 from .i18n import _
129 ParseError.__init__(self, _("unknown identifier: %s") % function)
129 ParseError.__init__(self, _("unknown identifier: %s") % function)
130 self.function = function
130 self.function = function
131 self.symbols = symbols
131 self.symbols = symbols
132
132
133 class RepoError(Hint, Exception):
133 class RepoError(Hint, Exception):
134 __bytes__ = _tobytes
134 __bytes__ = _tobytes
135
135
136 class RepoLookupError(RepoError):
136 class RepoLookupError(RepoError):
137 pass
137 pass
138
138
139 class FilteredRepoLookupError(RepoLookupError):
139 class FilteredRepoLookupError(RepoLookupError):
140 pass
140 pass
141
141
142 class CapabilityError(RepoError):
142 class CapabilityError(RepoError):
143 pass
143 pass
144
144
145 class RequirementError(RepoError):
145 class RequirementError(RepoError):
146 """Exception raised if .hg/requires has an unknown entry."""
146 """Exception raised if .hg/requires has an unknown entry."""
147
147
148 class StdioError(IOError):
148 class StdioError(IOError):
149 """Raised if I/O to stdout or stderr fails"""
149 """Raised if I/O to stdout or stderr fails"""
150
150
151 def __init__(self, err):
151 def __init__(self, err):
152 IOError.__init__(self, err.errno, err.strerror)
152 IOError.__init__(self, err.errno, err.strerror)
153
153
154 # no __bytes__() because error message is derived from the standard IOError
154 # no __bytes__() because error message is derived from the standard IOError
155
155
156 class UnsupportedMergeRecords(Abort):
156 class UnsupportedMergeRecords(Abort):
157 def __init__(self, recordtypes):
157 def __init__(self, recordtypes):
158 from .i18n import _
158 from .i18n import _
159 self.recordtypes = sorted(recordtypes)
159 self.recordtypes = sorted(recordtypes)
160 s = ' '.join(self.recordtypes)
160 s = ' '.join(self.recordtypes)
161 Abort.__init__(
161 Abort.__init__(
162 self, _('unsupported merge state records: %s') % s,
162 self, _('unsupported merge state records: %s') % s,
163 hint=_('see https://mercurial-scm.org/wiki/MergeStateRecords for '
163 hint=_('see https://mercurial-scm.org/wiki/MergeStateRecords for '
164 'more information'))
164 'more information'))
165
165
166 class UnknownVersion(Abort):
166 class UnknownVersion(Abort):
167 """generic exception for aborting from an encounter with an unknown version
167 """generic exception for aborting from an encounter with an unknown version
168 """
168 """
169
169
170 def __init__(self, msg, hint=None, version=None):
170 def __init__(self, msg, hint=None, version=None):
171 self.version = version
171 self.version = version
172 super(UnknownVersion, self).__init__(msg, hint=hint)
172 super(UnknownVersion, self).__init__(msg, hint=hint)
173
173
174 class LockError(IOError):
174 class LockError(IOError):
175 def __init__(self, errno, strerror, filename, desc):
175 def __init__(self, errno, strerror, filename, desc):
176 IOError.__init__(self, errno, strerror, filename)
176 IOError.__init__(self, errno, strerror, filename)
177 self.desc = desc
177 self.desc = desc
178
178
179 # no __bytes__() because error message is derived from the standard IOError
179 # no __bytes__() because error message is derived from the standard IOError
180
180
181 class LockHeld(LockError):
181 class LockHeld(LockError):
182 def __init__(self, errno, filename, desc, locker):
182 def __init__(self, errno, filename, desc, locker):
183 LockError.__init__(self, errno, 'Lock held', filename, desc)
183 LockError.__init__(self, errno, 'Lock held', filename, desc)
184 self.locker = locker
184 self.locker = locker
185
185
186 class LockUnavailable(LockError):
186 class LockUnavailable(LockError):
187 pass
187 pass
188
188
189 # LockError is for errors while acquiring the lock -- this is unrelated
189 # LockError is for errors while acquiring the lock -- this is unrelated
190 class LockInheritanceContractViolation(RuntimeError):
190 class LockInheritanceContractViolation(RuntimeError):
191 __bytes__ = _tobytes
191 __bytes__ = _tobytes
192
192
193 class ResponseError(Exception):
193 class ResponseError(Exception):
194 """Raised to print an error with part of output and exit."""
194 """Raised to print an error with part of output and exit."""
195 __bytes__ = _tobytes
195 __bytes__ = _tobytes
196
196
197 class UnknownCommand(Exception):
197 class UnknownCommand(Exception):
198 """Exception raised if command is not in the command table."""
198 """Exception raised if command is not in the command table."""
199 __bytes__ = _tobytes
199 __bytes__ = _tobytes
200
200
201 class AmbiguousCommand(Exception):
201 class AmbiguousCommand(Exception):
202 """Exception raised if command shortcut matches more than one command."""
202 """Exception raised if command shortcut matches more than one command."""
203 __bytes__ = _tobytes
203 __bytes__ = _tobytes
204
204
205 # derived from KeyboardInterrupt to simplify some breakout code
205 # derived from KeyboardInterrupt to simplify some breakout code
206 class SignalInterrupt(KeyboardInterrupt):
206 class SignalInterrupt(KeyboardInterrupt):
207 """Exception raised on SIGTERM and SIGHUP."""
207 """Exception raised on SIGTERM and SIGHUP."""
208
208
209 class SignatureError(Exception):
209 class SignatureError(Exception):
210 __bytes__ = _tobytes
210 __bytes__ = _tobytes
211
211
212 class PushRaced(RuntimeError):
212 class PushRaced(RuntimeError):
213 """An exception raised during unbundling that indicate a push race"""
213 """An exception raised during unbundling that indicate a push race"""
214 __bytes__ = _tobytes
214 __bytes__ = _tobytes
215
215
216 class ProgrammingError(Hint, RuntimeError):
216 class ProgrammingError(Hint, RuntimeError):
217 """Raised if a mercurial (core or extension) developer made a mistake"""
217 """Raised if a mercurial (core or extension) developer made a mistake"""
218
218
219 def __init__(self, msg, *args, **kwargs):
219 def __init__(self, msg, *args, **kwargs):
220 if not isinstance(msg, str):
220 # On Python 3, turn the message back into a string since this is
221 # This means we're on Python 3, because we got a
221 # an internal-only error that won't be printed except in a
222 # bytes. Turn the message back into a string since this is
222 # stack traces.
223 # an internal-only error that won't be printed except in a
223 msg = pycompat.sysstr(msg)
224 # stack traces.
225 msg = msg.decode('utf8')
226 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
224 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
227
225
228 __bytes__ = _tobytes
226 __bytes__ = _tobytes
229
227
230 class WdirUnsupported(Exception):
228 class WdirUnsupported(Exception):
231 """An exception which is raised when 'wdir()' is not supported"""
229 """An exception which is raised when 'wdir()' is not supported"""
232 __bytes__ = _tobytes
230 __bytes__ = _tobytes
233
231
234 # bundle2 related errors
232 # bundle2 related errors
235 class BundleValueError(ValueError):
233 class BundleValueError(ValueError):
236 """error raised when bundle2 cannot be processed"""
234 """error raised when bundle2 cannot be processed"""
237 __bytes__ = _tobytes
235 __bytes__ = _tobytes
238
236
239 class BundleUnknownFeatureError(BundleValueError):
237 class BundleUnknownFeatureError(BundleValueError):
240 def __init__(self, parttype=None, params=(), values=()):
238 def __init__(self, parttype=None, params=(), values=()):
241 self.parttype = parttype
239 self.parttype = parttype
242 self.params = params
240 self.params = params
243 self.values = values
241 self.values = values
244 if self.parttype is None:
242 if self.parttype is None:
245 msg = 'Stream Parameter'
243 msg = 'Stream Parameter'
246 else:
244 else:
247 msg = parttype
245 msg = parttype
248 entries = self.params
246 entries = self.params
249 if self.params and self.values:
247 if self.params and self.values:
250 assert len(self.params) == len(self.values)
248 assert len(self.params) == len(self.values)
251 entries = []
249 entries = []
252 for idx, par in enumerate(self.params):
250 for idx, par in enumerate(self.params):
253 val = self.values[idx]
251 val = self.values[idx]
254 if val is None:
252 if val is None:
255 entries.append(val)
253 entries.append(val)
256 else:
254 else:
257 entries.append("%s=%r" % (par, pycompat.maybebytestr(val)))
255 entries.append("%s=%r" % (par, pycompat.maybebytestr(val)))
258 if entries:
256 if entries:
259 msg = '%s - %s' % (msg, ', '.join(entries))
257 msg = '%s - %s' % (msg, ', '.join(entries))
260 ValueError.__init__(self, msg)
258 ValueError.__init__(self, msg)
261
259
262 class ReadOnlyPartError(RuntimeError):
260 class ReadOnlyPartError(RuntimeError):
263 """error raised when code tries to alter a part being generated"""
261 """error raised when code tries to alter a part being generated"""
264 __bytes__ = _tobytes
262 __bytes__ = _tobytes
265
263
266 class PushkeyFailed(Abort):
264 class PushkeyFailed(Abort):
267 """error raised when a pushkey part failed to update a value"""
265 """error raised when a pushkey part failed to update a value"""
268
266
269 def __init__(self, partid, namespace=None, key=None, new=None, old=None,
267 def __init__(self, partid, namespace=None, key=None, new=None, old=None,
270 ret=None):
268 ret=None):
271 self.partid = partid
269 self.partid = partid
272 self.namespace = namespace
270 self.namespace = namespace
273 self.key = key
271 self.key = key
274 self.new = new
272 self.new = new
275 self.old = old
273 self.old = old
276 self.ret = ret
274 self.ret = ret
277 # no i18n expected to be processed into a better message
275 # no i18n expected to be processed into a better message
278 Abort.__init__(self, 'failed to update value for "%s/%s"'
276 Abort.__init__(self, 'failed to update value for "%s/%s"'
279 % (namespace, key))
277 % (namespace, key))
280
278
281 class CensoredNodeError(RevlogError):
279 class CensoredNodeError(RevlogError):
282 """error raised when content verification fails on a censored node
280 """error raised when content verification fails on a censored node
283
281
284 Also contains the tombstone data substituted for the uncensored data.
282 Also contains the tombstone data substituted for the uncensored data.
285 """
283 """
286
284
287 def __init__(self, filename, node, tombstone):
285 def __init__(self, filename, node, tombstone):
288 from .node import short
286 from .node import short
289 RevlogError.__init__(self, '%s:%s' % (filename, short(node)))
287 RevlogError.__init__(self, '%s:%s' % (filename, short(node)))
290 self.tombstone = tombstone
288 self.tombstone = tombstone
291
289
292 class CensoredBaseError(RevlogError):
290 class CensoredBaseError(RevlogError):
293 """error raised when a delta is rejected because its base is censored
291 """error raised when a delta is rejected because its base is censored
294
292
295 A delta based on a censored revision must be formed as single patch
293 A delta based on a censored revision must be formed as single patch
296 operation which replaces the entire base with new content. This ensures
294 operation which replaces the entire base with new content. This ensures
297 the delta may be applied by clones which have not censored the base.
295 the delta may be applied by clones which have not censored the base.
298 """
296 """
299
297
300 class InvalidBundleSpecification(Exception):
298 class InvalidBundleSpecification(Exception):
301 """error raised when a bundle specification is invalid.
299 """error raised when a bundle specification is invalid.
302
300
303 This is used for syntax errors as opposed to support errors.
301 This is used for syntax errors as opposed to support errors.
304 """
302 """
305 __bytes__ = _tobytes
303 __bytes__ = _tobytes
306
304
307 class UnsupportedBundleSpecification(Exception):
305 class UnsupportedBundleSpecification(Exception):
308 """error raised when a bundle specification is not supported."""
306 """error raised when a bundle specification is not supported."""
309 __bytes__ = _tobytes
307 __bytes__ = _tobytes
310
308
311 class CorruptedState(Exception):
309 class CorruptedState(Exception):
312 """error raised when a command is not able to read its state from file"""
310 """error raised when a command is not able to read its state from file"""
313 __bytes__ = _tobytes
311 __bytes__ = _tobytes
314
312
315 class PeerTransportError(Abort):
313 class PeerTransportError(Abort):
316 """Transport-level I/O error when communicating with a peer repo."""
314 """Transport-level I/O error when communicating with a peer repo."""
317
315
318 class InMemoryMergeConflictsError(Exception):
316 class InMemoryMergeConflictsError(Exception):
319 """Exception raised when merge conflicts arose during an in-memory merge."""
317 """Exception raised when merge conflicts arose during an in-memory merge."""
320 __bytes__ = _tobytes
318 __bytes__ = _tobytes
321
319
322 class WireprotoCommandError(Exception):
320 class WireprotoCommandError(Exception):
323 """Represents an error during execution of a wire protocol command.
321 """Represents an error during execution of a wire protocol command.
324
322
325 Should only be thrown by wire protocol version 2 commands.
323 Should only be thrown by wire protocol version 2 commands.
326
324
327 The error is a formatter string and an optional iterable of arguments.
325 The error is a formatter string and an optional iterable of arguments.
328 """
326 """
329 def __init__(self, message, args=None):
327 def __init__(self, message, args=None):
330 self.message = message
328 self.message = message
331 self.messageargs = args
329 self.messageargs = args
General Comments 0
You need to be logged in to leave comments. Login now