~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/errors.py

  • Committer: Martin Pool
  • Date: 2005-09-05 09:11:03 UTC
  • Revision ID: mbp@sourcefrog.net-20050905091103-1e51e146be0f08b4
- add test for deserialization from a canned XML inventory

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# (C) 2005 Canonical
 
1
#! /usr/bin/env python
 
2
# -*- coding: UTF-8 -*-
2
3
 
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
14
15
# along with this program; if not, write to the Free Software
15
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
 
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
 
 
 
18
 
 
19
__copyright__ = "Copyright (C) 2005 Canonical Ltd."
 
20
__author__ = "Martin Pool <mbp@canonical.com>"
 
21
 
 
22
 
 
23
######################################################################
 
24
# exceptions 
68
25
class BzrError(StandardError):
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"""
 
26
    pass
 
27
 
 
28
class BzrCheckError(BzrError):
 
29
    pass
 
30
 
 
31
 
 
32
class InvalidRevisionNumber(BzrError):
120
33
    def __init__(self, revno):
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
 
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
139
42
 
140
43
 
141
44
class BzrCommandError(BzrError):
142
45
    # Error from malformed user command
143
 
    # This is being misused as a generic exception
144
 
    # pleae subclass. RBC 20051030
145
 
    #
146
 
    # I think it's a waste of effort to differentiate between errors that
147
 
    # are not intended to be caught anyway.  UI code need not subclass
148
 
    # BzrCommandError, and non-UI code should not throw a subclass of
149
 
    # BzrCommandError.  ADHB 20051211
150
 
    def __str__(self):
151
 
        return self.args[0]
152
 
 
153
 
 
154
 
class BzrOptionError(BzrCommandError):
155
 
    """Some missing or otherwise incorrect option was supplied."""
156
 
 
157
 
    
158
 
class StrictCommitFailed(Exception):
159
 
    """Commit refused because there are unknowns in the tree."""
160
 
 
161
 
 
162
 
class PathError(BzrNewError):
163
 
    """Generic path error: %(path)r%(extra)s)"""
164
 
    def __init__(self, path, extra=None):
165
 
        BzrNewError.__init__(self)
166
 
        self.path = path
167
 
        if extra:
168
 
            self.extra = ': ' + str(extra)
169
 
        else:
170
 
            self.extra = ''
171
 
 
172
 
 
173
 
class NoSuchFile(PathError):
174
 
    """No such file: %(path)r%(extra)s"""
175
 
 
176
 
 
177
 
class FileExists(PathError):
178
 
    """File exists: %(path)r%(extra)s"""
179
 
 
180
 
 
181
 
class PermissionDenied(PathError):
182
 
    """Permission denied: %(path)r%(extra)s"""
183
 
 
184
 
 
185
 
class PathNotChild(BzrNewError):
186
 
    """Path %(path)r is not a child of path %(base)r%(extra)s"""
187
 
    def __init__(self, path, base, extra=None):
188
 
        BzrNewError.__init__(self)
189
 
        self.path = path
190
 
        self.base = base
191
 
        if extra:
192
 
            self.extra = ': ' + str(extra)
193
 
        else:
194
 
            self.extra = ''
195
 
 
196
 
 
197
 
class NotBranchError(BzrNewError):
198
 
    """Not a branch: %(path)s"""
199
 
    def __init__(self, path):
200
 
        BzrNewError.__init__(self)
201
 
        self.path = path
202
 
 
203
 
 
204
 
class FileInWrongBranch(BzrNewError):
205
 
    """File %(path)s in not in branch %(branch_base)s."""
206
 
    def __init__(self, branch, path):
207
 
        BzrNewError.__init__(self)
208
 
        self.branch = branch
209
 
        self.branch_base = branch.base
210
 
        self.path = path
211
 
 
212
 
 
213
 
class UnsupportedFormatError(BzrError):
214
 
    """Specified path is a bzr branch that we cannot read."""
215
 
    def __str__(self):
216
 
        return 'unsupported branch format: %s' % self.args[0]
217
 
 
218
 
 
219
 
class NotVersionedError(BzrNewError):
220
 
    """%(path)s is not versioned"""
221
 
    def __init__(self, path):
222
 
        BzrNewError.__init__(self)
223
 
        self.path = path
 
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."""
224
56
 
225
57
 
226
58
class BadFileKindError(BzrError):
227
59
    """Specified file is of a kind that cannot be added.
228
60
 
229
61
    (For example a symlink or device file.)"""
 
62
    pass
230
63
 
231
64
 
232
65
class ForbiddenFileError(BzrError):
233
66
    """Cannot operate on a file because it is a control file."""
 
67
    pass
234
68
 
235
69
 
236
70
class LockError(Exception):
237
 
    """Lock error"""
238
 
    # All exceptions from the lock/unlock functions should be from
239
 
    # this exception class.  They will be translated as necessary. The
240
 
    # original exception is available as e.original_error
241
 
 
242
 
 
243
 
class CommitNotPossible(LockError):
244
 
    """A commit was attempted but we do not have a write lock open."""
245
 
 
246
 
 
247
 
class AlreadyCommitted(LockError):
248
 
    """A rollback was requested, but is not able to be accomplished."""
249
 
 
250
 
 
251
 
class ReadOnlyError(LockError):
252
 
    """A write attempt was made in a read only transaction."""
253
 
 
254
 
 
255
 
class PointlessCommit(BzrNewError):
256
 
    """No changes to commit"""
257
 
 
258
 
class StrictCommitFailed(Exception):
259
 
    """Commit refused because there are unknowns in the tree."""
 
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
 
260
86
 
261
87
class NoSuchRevision(BzrError):
262
88
    def __init__(self, branch, revision):
266
92
        BzrError.__init__(self, msg)
267
93
 
268
94
 
269
 
class HistoryMissing(BzrError):
270
 
    def __init__(self, branch, object_type, object_id):
271
 
        self.branch = branch
272
 
        BzrError.__init__(self,
273
 
                          '%s is missing %s {%s}'
274
 
                          % (branch, object_type, object_id))
275
 
 
276
 
 
277
 
class DivergedBranches(BzrError):
278
 
    def __init__(self, branch1, branch2):
279
 
        BzrError.__init__(self, "These branches have diverged.  Try merge.")
280
 
        self.branch1 = branch1
281
 
        self.branch2 = branch2
282
 
 
283
 
 
284
95
class UnrelatedBranches(BzrCommandError):
285
96
    def __init__(self):
286
97
        msg = "Branches have no common ancestor, and no base revision"\
287
98
            " specified."
288
99
        BzrCommandError.__init__(self, msg)
289
100
 
290
 
class NoCommonAncestor(BzrError):
291
 
    def __init__(self, revision_a, revision_b):
292
 
        msg = "Revisions have no common ancestor: %s %s." \
293
 
            % (revision_a, revision_b) 
294
 
        BzrError.__init__(self, msg)
295
 
 
296
 
class NoCommonRoot(BzrError):
297
 
    def __init__(self, revision_a, revision_b):
298
 
        msg = "Revisions are not derived from the same root: %s %s." \
299
 
            % (revision_a, revision_b) 
300
 
        BzrError.__init__(self, msg)
301
101
 
302
102
class NotAncestor(BzrError):
303
103
    def __init__(self, rev_id, not_ancestor_id):
 
104
        self.rev_id = rev_id
 
105
        self.not_ancestor_id = not_ancestor_id
304
106
        msg = "Revision %s is not an ancestor of %s" % (not_ancestor_id, 
305
107
                                                        rev_id)
306
108
        BzrError.__init__(self, msg)
307
 
        self.rev_id = rev_id
308
 
        self.not_ancestor_id = not_ancestor_id
309
109
 
310
110
 
311
111
class InstallFailed(BzrError):
312
112
    def __init__(self, revisions):
 
113
        self.revisions = revisions
313
114
        msg = "Could not install revisions:\n%s" % " ,".join(revisions)
314
115
        BzrError.__init__(self, msg)
315
 
        self.revisions = revisions
316
116
 
317
117
 
318
118
class AmbiguousBase(BzrError):
322
122
        BzrError.__init__(self, msg)
323
123
        self.bases = bases
324
124
 
325
 
class NoCommits(BzrError):
326
 
    def __init__(self, branch):
327
 
        msg = "Branch %s has no commits." % branch
328
 
        BzrError.__init__(self, msg)
329
 
 
330
 
class UnlistableStore(BzrError):
331
 
    def __init__(self, store):
332
 
        BzrError.__init__(self, "Store %s is not listable" % store)
333
 
 
334
 
class UnlistableBranch(BzrError):
335
 
    def __init__(self, br):
336
 
        BzrError.__init__(self, "Stores for branch %s are not listable" % br)
337
 
 
338
 
 
339
 
class WeaveError(BzrNewError):
340
 
    """Error in processing weave: %(message)s"""
341
 
    def __init__(self, message=None):
342
 
        BzrNewError.__init__(self)
343
 
        self.message = message
344
 
 
345
 
 
346
 
class WeaveRevisionAlreadyPresent(WeaveError):
347
 
    """Revision {%(revision_id)s} already present in %(weave)s"""
348
 
    def __init__(self, revision_id, weave):
349
 
        WeaveError.__init__(self)
350
 
        self.revision_id = revision_id
351
 
        self.weave = weave
352
 
 
353
 
 
354
 
class WeaveRevisionNotPresent(WeaveError):
355
 
    """Revision {%(revision_id)s} not present in %(weave)s"""
356
 
    def __init__(self, revision_id, weave):
357
 
        WeaveError.__init__(self)
358
 
        self.revision_id = revision_id
359
 
        self.weave = weave
360
 
 
361
 
 
362
 
class WeaveFormatError(WeaveError):
363
 
    """Weave invariant violated: %(what)s"""
364
 
    def __init__(self, what):
365
 
        WeaveError.__init__(self)
366
 
        self.what = what
367
 
 
368
 
 
369
 
class WeaveParentMismatch(WeaveError):
370
 
    """Parents are mismatched between two revisions."""
371
 
    
372
 
 
373
 
class NoSuchExportFormat(BzrNewError):
374
 
    """Export format %(format)r not supported"""
375
 
    def __init__(self, format):
376
 
        BzrNewError.__init__(self)
377
 
        self.format = format
378
 
 
379
 
 
380
 
class TransportError(BzrError):
381
 
    """All errors thrown by Transport implementations should derive
382
 
    from this class.
383
 
    """
384
 
    def __init__(self, msg=None, orig_error=None):
385
 
        if msg is None and orig_error is not None:
386
 
            msg = str(orig_error)
387
 
        BzrError.__init__(self, msg)
388
 
        self.msg = msg
389
 
        self.orig_error = orig_error
390
 
 
391
 
# A set of semi-meaningful errors which can be thrown
392
 
class TransportNotPossible(TransportError):
393
 
    """This is for transports where a specific function is explicitly not
394
 
    possible. Such as pushing files to an HTTP server.
395
 
    """
396
 
    pass
397
 
 
398
 
 
399
 
class ConnectionError(TransportError):
400
 
    """A connection problem prevents file retrieval.
401
 
    This does not indicate whether the file exists or not; it indicates that a
402
 
    precondition for requesting the file was not met.
403
 
    """
404
 
    def __init__(self, msg=None, orig_error=None):
405
 
        TransportError.__init__(self, msg=msg, orig_error=orig_error)
406
 
 
407
 
 
408
 
class ConnectionReset(TransportError):
409
 
    """The connection has been closed."""
410
 
    pass
411
 
 
412
 
class ConflictsInTree(BzrError):
413
 
    def __init__(self):
414
 
        BzrError.__init__(self, "Working tree has conflicts.")
415
 
 
416
 
class ParseConfigError(BzrError):
417
 
    def __init__(self, errors, filename):
418
 
        if filename is None:
419
 
            filename = ""
420
 
        message = "Error(s) parsing config file %s:\n%s" % \
421
 
            (filename, ('\n'.join(e.message for e in errors)))
422
 
        BzrError.__init__(self, message)
423
 
 
424
 
class SigningFailed(BzrError):
425
 
    def __init__(self, command_line):
426
 
        BzrError.__init__(self, "Failed to gpg sign data with command '%s'"
427
 
                               % command_line)
428
 
 
429
 
class WorkingTreeNotRevision(BzrError):
430
 
    def __init__(self, tree):
431
 
        BzrError.__init__(self, "The working tree for %s has changed since"
432
 
                          " last commit, but weave merge requires that it be"
433
 
                          " unchanged." % tree.basedir)
434
 
 
435
 
class CantReprocessAndShowBase(BzrNewError):
436
 
    """Can't reprocess and show base.
437
 
Reprocessing obscures relationship of conflicting lines to base."""
438
 
 
439
 
class GraphCycleError(BzrNewError):
440
 
    """Cycle in graph %(graph)r"""
441
 
    def __init__(self, graph):
442
 
        BzrNewError.__init__(self)
443
 
        self.graph = graph
444
 
 
445
 
class NotConflicted(BzrNewError):
446
 
    """File %(filename)s is not conflicted."""
447
 
    def __init__(self, filename):
448
 
        BzrNewError.__init__(self)
449
 
        self.filename = filename
450
 
 
451
 
class MustUseDecorated(Exception):
452
 
    """A decorating function has requested its original command be used.
453
 
    
454
 
    This should never escape bzr, so does not need to be printable.
455
 
    """
456
 
 
457
 
class MissingText(BzrNewError):
458
 
    """Branch %(base)s is missing revision %(text_revision)s of %(file_id)s"""
459
 
    def __init__(self, branch, text_revision, file_id):
460
 
        self.branch = branch
461
 
        self.base = branch.base
462
 
        self.text_revision = text_revision
463
 
        self.file_id = file_id