~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/errors.py

[merge] robertc's integration, updated tests to check for retcode=3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#! /usr/bin/env python
2
 
# -*- coding: UTF-8 -*-
 
1
# (C) 2005 Canonical
3
2
 
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
15
14
# along with this program; if not, write to the Free Software
16
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
16
 
18
 
 
19
 
__copyright__ = "Copyright (C) 2005 Canonical Ltd."
20
 
__author__ = "Martin Pool <mbp@canonical.com>"
21
 
 
22
 
 
23
 
######################################################################
24
 
# exceptions 
 
17
"""Exceptions for bzr, and reporting of them.
 
18
 
 
19
Exceptions are caught at a high level to report errors to the user, and
 
20
might also be caught inside the program.  Therefore it needs to be
 
21
possible to convert them to a meaningful string, and also for them to be
 
22
interrogated by the program.
 
23
 
 
24
Exceptions are defined such that the arguments given to the constructor
 
25
are stored in the object as properties of the same name.  When the
 
26
object is printed as a string, the doc string of the class is used as
 
27
a format string with the property dictionary available to it.
 
28
 
 
29
This means that exceptions can used like this:
 
30
 
 
31
>>> import sys
 
32
>>> try:
 
33
...   raise NotBranchError(path='/foo/bar')
 
34
... except:
 
35
...   print sys.exc_type
 
36
...   print sys.exc_value
 
37
...   print sys.exc_value.path
 
38
bzrlib.errors.NotBranchError
 
39
Not a branch: /foo/bar
 
40
/foo/bar
 
41
 
 
42
Therefore:
 
43
 
 
44
 * create a new exception class for any class of error that can be
 
45
   usefully distinguished.
 
46
 
 
47
 * the printable form of an exception is generated by the base class
 
48
   __str__ method
 
49
 
 
50
Exception strings should start with a capital letter and not have a final
 
51
fullstop.
 
52
"""
 
53
 
 
54
# based on Scott James Remnant's hct error classes
 
55
 
 
56
# TODO: is there any value in providing the .args field used by standard
 
57
# python exceptions?   A list of values with no names seems less useful 
 
58
# to me.
 
59
 
 
60
# TODO: Perhaps convert the exception to a string at the moment it's 
 
61
# constructed to make sure it will succeed.  But that says nothing about
 
62
# exceptions that are never raised.
 
63
 
 
64
# TODO: Convert all the other error classes here to BzrNewError, and eliminate
 
65
# the old one.
 
66
 
 
67
 
25
68
class BzrError(StandardError):
26
 
    pass
27
 
 
28
 
class BzrCheckError(BzrError):
29
 
    pass
30
 
 
31
 
 
32
 
class InvalidRevisionNumber(BzrError):
 
69
    def __str__(self):
 
70
        # XXX: Should we show the exception class in 
 
71
        # exceptions that don't provide their own message?  
 
72
        # maybe it should be done at a higher level
 
73
        ## n = self.__class__.__name__ + ': '
 
74
        n = ''
 
75
        if len(self.args) == 1:
 
76
            return str(self.args[0])
 
77
        elif len(self.args) == 2:
 
78
            # further explanation or suggestions
 
79
            try:
 
80
                return n + '\n  '.join([self.args[0]] + self.args[1])
 
81
            except TypeError:
 
82
                return n + "%r" % self
 
83
        else:
 
84
            return n + `self.args`
 
85
 
 
86
 
 
87
class BzrNewError(BzrError):
 
88
    """bzr error"""
 
89
    # base classes should override the docstring with their human-
 
90
    # readable explanation
 
91
 
 
92
    def __init__(self, **kwds):
 
93
        for key, value in kwds.items():
 
94
            setattr(self, key, value)
 
95
 
 
96
    def __str__(self):
 
97
        try:
 
98
            return self.__doc__ % self.__dict__
 
99
        except (NameError, ValueError, KeyError), e:
 
100
            return 'Unprintable exception %s: %s' \
 
101
                % (self.__class__.__name__, str(e))
 
102
 
 
103
 
 
104
class BzrCheckError(BzrNewError):
 
105
    """Internal check failed: %(message)s"""
 
106
    def __init__(self, message):
 
107
        BzrNewError.__init__(self)
 
108
        self.message = message
 
109
 
 
110
 
 
111
class InvalidEntryName(BzrNewError):
 
112
    """Invalid entry name: %(name)s"""
 
113
    def __init__(self, name):
 
114
        BzrNewError.__init__(self)
 
115
        self.name = name
 
116
 
 
117
 
 
118
class InvalidRevisionNumber(BzrNewError):
 
119
    """Invalid revision number %(revno)d"""
33
120
    def __init__(self, revno):
34
 
        self.args = [revno]
35
 
        
36
 
    def __str__(self):
37
 
        return 'invalid revision number: %r' % self.args[0]
38
 
 
39
 
 
40
 
class InvalidRevisionId(BzrError):
41
 
    pass
 
121
        BzrNewError.__init__(self)
 
122
        self.revno = revno
 
123
 
 
124
 
 
125
class InvalidRevisionId(BzrNewError):
 
126
    """Invalid revision-id {%(revision_id)s} in %(branch)s"""
 
127
    def __init__(self, revision_id, branch):
 
128
        BzrNewError.__init__(self)
 
129
        self.revision_id = revision_id
 
130
        self.branch = branch
 
131
 
 
132
 
 
133
class NoWorkingTree(BzrNewError):
 
134
    """No WorkingTree exists for %s(base)."""
 
135
    
 
136
    def __init__(self, base):
 
137
        BzrNewError.__init__(self)
 
138
        self.base = base
42
139
 
43
140
 
44
141
class BzrCommandError(BzrError):
45
142
    # Error from malformed user command
46
 
    pass
47
 
 
48
 
 
49
 
class NotBranchError(BzrError):
50
 
    """Specified path is not in a branch"""
51
 
    pass
52
 
 
53
 
 
54
 
class NotVersionedError(BzrError):
55
 
    """Specified object is not versioned."""
 
143
    # This is being misused as a generic exception
 
144
    # pleae subclass. RBC 20051030
 
145
    def __str__(self):
 
146
        return self.args[0]
 
147
 
 
148
 
 
149
class BzrOptionError(BzrCommandError):
 
150
    """Some missing or otherwise incorrect option was supplied."""
 
151
 
 
152
    
 
153
class StrictCommitFailed(Exception):
 
154
    """Commit refused because there are unknowns in the tree."""
 
155
 
 
156
class NotBranchError(BzrNewError):
 
157
    """Not a branch: %(path)s"""
 
158
    def __init__(self, path):
 
159
        BzrNewError.__init__(self)
 
160
        self.path = path
 
161
 
 
162
 
 
163
class UnsupportedFormatError(BzrError):
 
164
    """Specified path is a bzr branch that we cannot read."""
 
165
    def __str__(self):
 
166
        return 'unsupported branch format: %s' % self.args[0]
 
167
 
 
168
 
 
169
class NotVersionedError(BzrNewError):
 
170
    """%(path)s is not versioned"""
 
171
    def __init__(self, path):
 
172
        BzrNewError.__init__(self)
 
173
        self.path = path
56
174
 
57
175
 
58
176
class BadFileKindError(BzrError):
59
177
    """Specified file is of a kind that cannot be added.
60
178
 
61
179
    (For example a symlink or device file.)"""
62
 
    pass
63
180
 
64
181
 
65
182
class ForbiddenFileError(BzrError):
66
183
    """Cannot operate on a file because it is a control file."""
67
 
    pass
68
184
 
69
185
 
70
186
class LockError(Exception):
71
 
    """All exceptions from the lock/unlock functions should be from
72
 
    this exception class.  They will be translated as necessary. The
73
 
    original exception is available as e.original_error
74
 
    """
75
 
    def __init__(self, e=None):
76
 
        self.original_error = e
77
 
        if e:
78
 
            Exception.__init__(self, e)
79
 
        else:
80
 
            Exception.__init__(self)
81
 
 
82
 
 
83
 
class PointlessCommit(Exception):
84
 
    """Commit failed because nothing was changed."""
85
 
 
 
187
    """Lock error"""
 
188
    # All exceptions from the lock/unlock functions should be from
 
189
    # this exception class.  They will be translated as necessary. The
 
190
    # original exception is available as e.original_error
 
191
 
 
192
 
 
193
class CommitNotPossible(LockError):
 
194
    """A commit was attempted but we do not have a write lock open."""
 
195
 
 
196
 
 
197
class AlreadyCommitted(LockError):
 
198
    """A rollback was requested, but is not able to be accomplished."""
 
199
 
 
200
 
 
201
class ReadOnlyError(LockError):
 
202
    """A write attempt was made in a read only transaction."""
 
203
 
 
204
 
 
205
class PointlessCommit(BzrNewError):
 
206
    """No changes to commit"""
 
207
 
 
208
class StrictCommitFailed(Exception):
 
209
    """Commit refused because there are unknowns in the tree."""
 
210
 
 
211
class CannotBind(BzrNewError):
 
212
    """Cannot bind: %(msg)s"""
 
213
    def __init__(self, msg):
 
214
        BzrNewError.__init__(self)
 
215
        self.msg = msg
 
216
 
 
217
class CannotInstallRevisions(BzrNewError):
 
218
    """Cannot install revisions: %(msg)s"""
 
219
    def __init__(self, msg):
 
220
        BzrNewError.__init__(self)
 
221
        self.msg = msg
86
222
 
87
223
class NoSuchRevision(BzrError):
88
224
    def __init__(self, branch, revision):
92
228
        BzrError.__init__(self, msg)
93
229
 
94
230
 
 
231
class HistoryMissing(BzrError):
 
232
    def __init__(self, branch, object_type, object_id):
 
233
        self.branch = branch
 
234
        BzrError.__init__(self,
 
235
                          '%s is missing %s {%s}'
 
236
                          % (branch, object_type, object_id))
 
237
 
 
238
 
 
239
class DivergedBranches(BzrError):
 
240
    def __init__(self, branch1, branch2):
 
241
        BzrError.__init__(self, "These branches have diverged.")
 
242
        self.branch1 = branch1
 
243
        self.branch2 = branch2
 
244
 
 
245
 
95
246
class UnrelatedBranches(BzrCommandError):
96
247
    def __init__(self):
97
248
        msg = "Branches have no common ancestor, and no base revision"\
98
249
            " specified."
99
250
        BzrCommandError.__init__(self, msg)
100
251
 
 
252
class NoCommonAncestor(BzrError):
 
253
    def __init__(self, revision_a, revision_b):
 
254
        msg = "Revisions have no common ancestor: %s %s." \
 
255
            % (revision_a, revision_b) 
 
256
        BzrError.__init__(self, msg)
 
257
 
 
258
class NoCommonRoot(BzrError):
 
259
    def __init__(self, revision_a, revision_b):
 
260
        msg = "Revisions are not derived from the same root: %s %s." \
 
261
            % (revision_a, revision_b) 
 
262
        BzrError.__init__(self, msg)
 
263
 
 
264
class NotAncestor(BzrError):
 
265
    def __init__(self, rev_id, not_ancestor_id):
 
266
        msg = "Revision %s is not an ancestor of %s" % (not_ancestor_id, 
 
267
                                                        rev_id)
 
268
        BzrError.__init__(self, msg)
 
269
        self.rev_id = rev_id
 
270
        self.not_ancestor_id = not_ancestor_id
 
271
 
101
272
 
102
273
class NotAncestor(BzrError):
103
274
    def __init__(self, rev_id, not_ancestor_id):
110
281
 
111
282
class InstallFailed(BzrError):
112
283
    def __init__(self, revisions):
 
284
        msg = "Could not install revisions:\n%s" % " ,".join(revisions)
 
285
        BzrError.__init__(self, msg)
113
286
        self.revisions = revisions
114
 
        msg = "Could not install revisions:\n%s" % " ,".join(revisions)
115
 
        BzrError.__init__(self, msg)
116
287
 
117
288
 
118
289
class AmbiguousBase(BzrError):
122
293
        BzrError.__init__(self, msg)
123
294
        self.bases = bases
124
295
 
 
296
class NoCommits(BzrError):
 
297
    def __init__(self, branch):
 
298
        msg = "Branch %s has no commits." % branch
 
299
        BzrError.__init__(self, msg)
 
300
 
 
301
class UnlistableStore(BzrError):
 
302
    def __init__(self, store):
 
303
        BzrError.__init__(self, "Store %s is not listable" % store)
 
304
 
 
305
class UnlistableBranch(BzrError):
 
306
    def __init__(self, br):
 
307
        BzrError.__init__(self, "Stores for branch %s are not listable" % br)
 
308
 
 
309
 
 
310
class WeaveError(BzrNewError):
 
311
    """Error in processing weave: %(message)s"""
 
312
    def __init__(self, message=None):
 
313
        BzrNewError.__init__(self)
 
314
        self.message = message
 
315
 
 
316
 
 
317
class WeaveRevisionAlreadyPresent(WeaveError):
 
318
    """Revision {%(revision_id)s} already present in %(weave)s"""
 
319
    def __init__(self, revision_id, weave):
 
320
        WeaveError.__init__(self)
 
321
        self.revision_id = revision_id
 
322
        self.weave = weave
 
323
 
 
324
 
 
325
class WeaveRevisionNotPresent(WeaveError):
 
326
    """Revision {%(revision_id)s} not present in %(weave)s"""
 
327
    def __init__(self, revision_id, weave):
 
328
        WeaveError.__init__(self)
 
329
        self.revision_id = revision_id
 
330
        self.weave = weave
 
331
 
 
332
 
 
333
class WeaveFormatError(WeaveError):
 
334
    """Weave invariant violated: %(what)s"""
 
335
    def __init__(self, what):
 
336
        WeaveError.__init__(self)
 
337
        self.what = what
 
338
 
 
339
 
 
340
class WeaveParentMismatch(WeaveError):
 
341
    """Parents are mismatched between two revisions."""
 
342
    
 
343
 
 
344
class NoSuchExportFormat(BzrNewError):
 
345
    """Export format %(format)r not supported"""
 
346
    def __init__(self, format):
 
347
        BzrNewError.__init__(self)
 
348
        self.format = format
 
349
 
 
350
 
 
351
class TransportError(BzrError):
 
352
    """All errors thrown by Transport implementations should derive
 
353
    from this class.
 
354
    """
 
355
    def __init__(self, msg=None, orig_error=None):
 
356
        if msg is None and orig_error is not None:
 
357
            msg = str(orig_error)
 
358
        BzrError.__init__(self, msg)
 
359
        self.msg = msg
 
360
        self.orig_error = orig_error
 
361
 
 
362
# A set of semi-meaningful errors which can be thrown
 
363
class TransportNotPossible(TransportError):
 
364
    """This is for transports where a specific function is explicitly not
 
365
    possible. Such as pushing files to an HTTP server.
 
366
    """
 
367
    pass
 
368
 
 
369
class NonRelativePath(TransportError):
 
370
    """An absolute path was supplied, that could not be decoded into
 
371
    a relative path.
 
372
    """
 
373
    pass
 
374
 
 
375
class NoSuchFile(TransportError, IOError):
 
376
    """A get() was issued for a file that doesn't exist."""
 
377
 
 
378
    # XXX: Is multiple inheritance for exceptions really needed?
 
379
 
 
380
    def __str__(self):
 
381
        return 'no such file: ' + self.msg
 
382
 
 
383
    def __init__(self, msg=None, orig_error=None):
 
384
        import errno
 
385
        TransportError.__init__(self, msg=msg, orig_error=orig_error)
 
386
        IOError.__init__(self, errno.ENOENT, self.msg)
 
387
 
 
388
class ConnectionError(TransportError, IOError):
 
389
    """
 
390
    A connection problem prevents file retrieval.
 
391
    This does not indicate whether the file exists or not; it indicates that a
 
392
    precondition for requesting the file was not met.
 
393
    """
 
394
 
 
395
    # XXX: Is multiple inheritance for exceptions really needed?
 
396
 
 
397
    def __str__(self):
 
398
        return 'connection error: ' + self.msg
 
399
 
 
400
    def __init__(self, msg=None, orig_error=None):
 
401
        import errno
 
402
        TransportError.__init__(self, msg=msg, orig_error=orig_error)
 
403
        IOError.__init__(self, errno.ENOENT, self.msg)
 
404
 
 
405
 
 
406
class FileExists(TransportError, OSError):
 
407
    """An operation was attempted, which would overwrite an entry,
 
408
    but overwritting is not supported.
 
409
 
 
410
    mkdir() can throw this, but put() just overwites existing files.
 
411
    """
 
412
    # XXX: Is multiple inheritance for exceptions really needed?
 
413
    def __init__(self, msg=None, orig_error=None):
 
414
        import errno
 
415
        TransportError.__init__(self, msg=msg, orig_error=orig_error)
 
416
        OSError.__init__(self, errno.EEXIST, self.msg)
 
417
 
 
418
class PermissionDenied(TransportError):
 
419
    """An operation cannot succeed because of a lack of permissions."""
 
420
    pass
 
421
 
 
422
class ConnectionReset(TransportError):
 
423
    """The connection has been closed."""
 
424
    pass
 
425
 
 
426
class ConflictsInTree(BzrError):
 
427
    def __init__(self):
 
428
        BzrError.__init__(self, "Working tree has conflicts.")
 
429
 
 
430
class ParseConfigError(BzrError):
 
431
    def __init__(self, errors, filename):
 
432
        if filename is None:
 
433
            filename = ""
 
434
        message = "Error(s) parsing config file %s:\n%s" % \
 
435
            (filename, ('\n'.join(e.message for e in errors)))
 
436
        BzrError.__init__(self, message)
 
437
 
 
438
class SigningFailed(BzrError):
 
439
    def __init__(self, command_line):
 
440
        BzrError.__init__(self, "Failed to gpg sign data with command '%s'"
 
441
                               % command_line)
 
442
 
 
443
class WorkingTreeNotRevision(BzrError):
 
444
    def __init__(self, tree):
 
445
        BzrError.__init__(self, "The working tree for %s has changed since"
 
446
                          " last commit, but weave merge requires that it be"
 
447
                          " unchanged." % tree.basedir)
 
448
 
 
449
class CantReprocessAndShowBase(BzrNewError):
 
450
    """Can't reprocess and show base.
 
451
Reprocessing obscures relationship of conflicting lines to base."""
 
452
 
 
453
class GraphCycleError(BzrNewError):
 
454
    """Cycle in graph %(graph)r"""
 
455
    def __init__(self, graph):
 
456
        BzrNewError.__init__(self)
 
457
        self.graph = graph
 
458
 
 
459
class NotConflicted(BzrNewError):
 
460
    """File %(filename)s is not conflicted."""
 
461
    def __init__(self, filename):
 
462
        BzrNewError.__init__(self)
 
463
        self.filename = filename
 
464
 
 
465
class MustUseDecorated(Exception):
 
466
    """A decorating function has requested its original command be used.
 
467
    
 
468
    This should never escape bzr, so does not need to be printable.
 
469
    """
 
470