~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/errors.py

- start introducing hct error classes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#! /usr/bin/env python
2
1
# -*- coding: UTF-8 -*-
3
2
 
4
3
# This program is free software; you can redistribute it and/or modify
16
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
16
 
18
17
 
19
 
__copyright__ = "Copyright (C) 2005 Canonical Ltd."
20
 
__author__ = "Martin Pool <mbp@canonical.com>"
21
 
 
22
 
 
23
 
######################################################################
24
 
# exceptions 
 
18
# TODO: Change to a standard exception pattern: 
 
19
#
 
20
# - docstring of exceptions is a template for formatting the exception
 
21
#   so the __str__ method can be defined only in the superclass
 
22
# - the arguments to the exception are interpolated into this string
 
23
#
 
24
# when printing the exception we'd then require special handling only
 
25
# for built-in exceptions with no decent __str__ method, such as 
 
26
# ValueError and AssertionError.  See 
 
27
# scott@canonical.com--2005/hct--devel--0.10 util/errors.py
 
28
 
 
29
 
 
30
"""Exceptions for bzr, and reporting of them.
 
31
 
 
32
Exceptions are caught at a high level to report errors to the user, and
 
33
might also be caught inside the program.  Therefore it needs to be
 
34
possible to convert them to a meaningful string, and also for them to be
 
35
interrogated by the program.
 
36
 
 
37
Exceptions are defined such that the arguments given to the constructor
 
38
are stored in the object as properties of the same name.  When the
 
39
object is printed as a string, the doc string of the class is used as
 
40
a format string with the property dictionary available to it.
 
41
 
 
42
This means that exceptions can used like this:
 
43
 
 
44
>>> import sys
 
45
>>> try:
 
46
...   raise NotBranchError(path='/foo/bar')
 
47
... except:
 
48
...   print sys.exc_type
 
49
...   print sys.exc_value
 
50
...   print sys.exc_value.path
 
51
bzrlib.errors.NotBranchError
 
52
Not a branch: /foo/bar
 
53
/foo/bar
 
54
 
 
55
Therefore:
 
56
 
 
57
 * create a new exception class for any class of error that can be
 
58
   usefully distinguished.
 
59
 
 
60
 * the printable form of an exception is generated by the base class
 
61
   __str__ method
 
62
"""
 
63
 
 
64
# based on Scott James Remnant's hct error classes
 
65
 
 
66
 
25
67
class BzrError(StandardError):
26
 
    pass
 
68
    def __str__(self):
 
69
        # XXX: Should we show the exception class in 
 
70
        # exceptions that don't provide their own message?  
 
71
        # maybe it should be done at a higher level
 
72
        ## n = self.__class__.__name__ + ': '
 
73
        n = ''
 
74
        if len(self.args) == 1:
 
75
            return str(self.args[0])
 
76
        elif len(self.args) == 2:
 
77
            # further explanation or suggestions
 
78
            try:
 
79
                return n + '\n  '.join([self.args[0]] + self.args[1])
 
80
            except TypeError:
 
81
                return n + "%r" % self
 
82
        else:
 
83
            return n + `self.args`
 
84
 
 
85
 
 
86
class BzrNewError(Exception):
 
87
    """bzr error"""
 
88
    # base classes should override the docstring with their human-
 
89
    # readable explanation
 
90
 
 
91
    def __init__(self, **kwds):
 
92
        for key, value in kwds.items():
 
93
            setattr(self, key, value)
 
94
 
 
95
    def __str__(self):
 
96
        try:
 
97
            return self.__doc__ % self.__dict__
 
98
        except (NameError, ValueError, KeyError), e:
 
99
            return 'Unprintable exception %s: %s' \
 
100
                % (self.__class__.__name__, str(e))
 
101
 
27
102
 
28
103
class BzrCheckError(BzrError):
29
104
    pass
30
105
 
31
106
 
32
107
class InvalidRevisionNumber(BzrError):
33
 
    def __init__(self, revno):
34
 
        self.args = [revno]
35
 
        
36
108
    def __str__(self):
37
109
        return 'invalid revision number: %r' % self.args[0]
38
110
 
43
115
 
44
116
class BzrCommandError(BzrError):
45
117
    # Error from malformed user command
46
 
    pass
 
118
    def __str__(self):
 
119
        return self.args[0]
47
120
 
48
121
 
49
122
class NotBranchError(BzrError):
50
123
    """Specified path is not in a branch"""
51
 
    pass
 
124
    def __init__(self, path):
 
125
        BzrError.__init__(self, path)
 
126
 
 
127
    def __str__(self):
 
128
        return 'not a branch: %s' % self.args[0]
 
129
 
 
130
## class NotBranchError(BzrNewError):
 
131
##     """Not a branch: %(path)s"""
 
132
##     def __init__(self, path):
 
133
##         BzrNewError.__init__(self)
 
134
##         self.path = path
 
135
## 
 
136
 
 
137
class UnsupportedFormatError(BzrError):
 
138
    """Specified path is a bzr branch that we cannot read."""
 
139
    def __str__(self):
 
140
        return 'unsupported branch format: %s' % self.args[0]
52
141
 
53
142
 
54
143
class NotVersionedError(BzrError):
80
169
            Exception.__init__(self)
81
170
 
82
171
 
 
172
class CommitNotPossible(LockError):
 
173
    """A commit was attempted but we do not have a write lock open."""
 
174
 
 
175
 
 
176
class AlreadyCommitted(LockError):
 
177
    """A rollback was requested, but is not able to be accomplished."""
 
178
 
 
179
 
 
180
class ReadOnlyError(LockError):
 
181
    """A write attempt was made in a read only transaction."""
 
182
 
 
183
 
83
184
class PointlessCommit(Exception):
84
185
    """Commit failed because nothing was changed."""
85
186
 
92
193
        BzrError.__init__(self, msg)
93
194
 
94
195
 
 
196
class HistoryMissing(BzrError):
 
197
    def __init__(self, branch, object_type, object_id):
 
198
        self.branch = branch
 
199
        BzrError.__init__(self,
 
200
                          '%s is missing %s {%s}'
 
201
                          % (branch, object_type, object_id))
 
202
 
 
203
 
 
204
class DivergedBranches(BzrError):
 
205
    def __init__(self, branch1, branch2):
 
206
        BzrError.__init__(self, "These branches have diverged.")
 
207
        self.branch1 = branch1
 
208
        self.branch2 = branch2
 
209
 
 
210
 
 
211
class UnrelatedBranches(BzrCommandError):
 
212
    def __init__(self):
 
213
        msg = "Branches have no common ancestor, and no base revision"\
 
214
            " specified."
 
215
        BzrCommandError.__init__(self, msg)
 
216
 
 
217
class NoCommonAncestor(BzrError):
 
218
    def __init__(self, revision_a, revision_b):
 
219
        msg = "Revisions have no common ancestor: %s %s." \
 
220
            % (revision_a, revision_b) 
 
221
        BzrError.__init__(self, msg)
 
222
 
 
223
class NoCommonRoot(BzrError):
 
224
    def __init__(self, revision_a, revision_b):
 
225
        msg = "Revisions are not derived from the same root: %s %s." \
 
226
            % (revision_a, revision_b) 
 
227
        BzrError.__init__(self, msg)
 
228
 
 
229
class NotAncestor(BzrError):
 
230
    def __init__(self, rev_id, not_ancestor_id):
 
231
        msg = "Revision %s is not an ancestor of %s" % (not_ancestor_id, 
 
232
                                                        rev_id)
 
233
        BzrError.__init__(self, msg)
 
234
        self.rev_id = rev_id
 
235
        self.not_ancestor_id = not_ancestor_id
 
236
 
 
237
 
 
238
class NotAncestor(BzrError):
 
239
    def __init__(self, rev_id, not_ancestor_id):
 
240
        self.rev_id = rev_id
 
241
        self.not_ancestor_id = not_ancestor_id
 
242
        msg = "Revision %s is not an ancestor of %s" % (not_ancestor_id, 
 
243
                                                        rev_id)
 
244
        BzrError.__init__(self, msg)
 
245
 
 
246
 
 
247
class InstallFailed(BzrError):
 
248
    def __init__(self, revisions):
 
249
        msg = "Could not install revisions:\n%s" % " ,".join(revisions)
 
250
        BzrError.__init__(self, msg)
 
251
        self.revisions = revisions
 
252
 
 
253
 
 
254
class AmbiguousBase(BzrError):
 
255
    def __init__(self, bases):
 
256
        msg = "The correct base is unclear, becase %s are all equally close" %\
 
257
            ", ".join(bases)
 
258
        BzrError.__init__(self, msg)
 
259
        self.bases = bases
 
260
 
 
261
class NoCommits(BzrError):
 
262
    def __init__(self, branch):
 
263
        msg = "Branch %s has no commits." % branch
 
264
        BzrError.__init__(self, msg)
 
265
 
 
266
class UnlistableStore(BzrError):
 
267
    def __init__(self, store):
 
268
        BzrError.__init__(self, "Store %s is not listable" % store)
 
269
 
 
270
class UnlistableBranch(BzrError):
 
271
    def __init__(self, br):
 
272
        BzrError.__init__(self, "Stores for branch %s are not listable" % br)
 
273
 
 
274
 
 
275
from bzrlib.weave import WeaveError, WeaveParentMismatch
 
276
 
 
277
class TransportError(BzrError):
 
278
    """All errors thrown by Transport implementations should derive
 
279
    from this class.
 
280
    """
 
281
    def __init__(self, msg=None, orig_error=None):
 
282
        if msg is None and orig_error is not None:
 
283
            msg = str(orig_error)
 
284
        BzrError.__init__(self, msg)
 
285
        self.msg = msg
 
286
        self.orig_error = orig_error
 
287
 
 
288
# A set of semi-meaningful errors which can be thrown
 
289
class TransportNotPossible(TransportError):
 
290
    """This is for transports where a specific function is explicitly not
 
291
    possible. Such as pushing files to an HTTP server.
 
292
    """
 
293
    pass
 
294
 
 
295
class NonRelativePath(TransportError):
 
296
    """An absolute path was supplied, that could not be decoded into
 
297
    a relative path.
 
298
    """
 
299
    pass
 
300
 
 
301
class NoSuchFile(TransportError, IOError):
 
302
    """A get() was issued for a file that doesn't exist."""
 
303
 
 
304
    # XXX: Is multiple inheritance for exceptions really needed?
 
305
 
 
306
    def __str__(self):
 
307
        return 'no such file: ' + self.msg
 
308
 
 
309
    def __init__(self, msg=None, orig_error=None):
 
310
        import errno
 
311
        TransportError.__init__(self, msg=msg, orig_error=orig_error)
 
312
        IOError.__init__(self, errno.ENOENT, self.msg)
 
313
 
 
314
class FileExists(TransportError, OSError):
 
315
    """An operation was attempted, which would overwrite an entry,
 
316
    but overwritting is not supported.
 
317
 
 
318
    mkdir() can throw this, but put() just overwites existing files.
 
319
    """
 
320
    # XXX: Is multiple inheritance for exceptions really needed?
 
321
    def __init__(self, msg=None, orig_error=None):
 
322
        import errno
 
323
        TransportError.__init__(self, msg=msg, orig_error=orig_error)
 
324
        OSError.__init__(self, errno.EEXIST, self.msg)
 
325
 
 
326
class PermissionDenied(TransportError):
 
327
    """An operation cannot succeed because of a lack of permissions."""
 
328
    pass
 
329
 
 
330
class ConnectionReset(TransportError):
 
331
    """The connection has been closed."""
 
332
    pass
 
333
 
 
334
class ConflictsInTree(BzrError):
 
335
    def __init__(self):
 
336
        BzrError.__init__(self, "Working tree has conflicts.")