1
1
# Copyright (C) 2005, 2006 Canonical
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Exceptions for bzr, and reporting of them.
19
There are 3 different classes of error:
21
* KeyboardInterrupt, and OSError with EPIPE - the program terminates
22
with an appropriate short message
24
* User errors, indicating a problem caused by the user such as a bad URL.
25
These are printed in a short form.
27
* Internal unexpected errors, including most Python builtin errors
28
and some raised from inside bzr. These are printed with a full
29
traceback and an invitation to report the bug.
19
31
Exceptions are caught at a high level to report errors to the user, and
20
32
might also be caught inside the program. Therefore it needs to be
21
33
possible to convert them to a meaningful string, and also for them to be
46
58
* create a new exception class for any class of error that can be
47
usefully distinguished.
49
* the printable form of an exception is generated by the base class
52
Exception strings should start with a capital letter and not have a final
59
usefully distinguished. If no callers are likely to want to catch
60
one but not another, don't worry about them.
62
* the __str__ method should generate something useful; BzrError provides
63
a good default implementation
65
Exception strings should start with a capital letter and should not have a
56
69
from warnings import warn
71
from bzrlib.patches import (PatchSyntax,
58
78
# based on Scott James Remnant's hct error classes
60
80
# TODO: is there any value in providing the .args field used by standard
68
88
# TODO: Convert all the other error classes here to BzrNewError, and eliminate
91
# TODO: The pattern (from hct) of using classes docstrings as message
92
# templates is cute but maybe not such a great idea - perhaps should have a
93
# separate static message_template.
72
96
class BzrError(StandardError):
73
100
def __str__(self):
74
101
# XXX: Should we show the exception class in
75
102
# exceptions that don't provide their own message?
100
127
def __str__(self):
102
return self.__doc__ % self.__dict__
129
# __str__() should always return a 'str' object
130
# never a 'unicode' object.
131
s = self.__doc__ % self.__dict__
132
if isinstance(s, unicode):
133
return s.encode('utf8')
103
135
except (NameError, ValueError, KeyError), e:
104
136
return 'Unprintable exception %s: %s' \
105
137
% (self.__class__.__name__, str(e))
130
167
class InvalidRevisionId(BzrNewError):
131
168
"""Invalid revision-id {%(revision_id)s} in %(branch)s"""
132
169
def __init__(self, revision_id, branch):
170
# branch can be any string or object with __str__ defined
133
171
BzrNewError.__init__(self)
134
172
self.revision_id = revision_id
135
173
self.branch = branch
138
176
class NoWorkingTree(BzrNewError):
139
"""No WorkingTree exists for %s(base)."""
177
"""No WorkingTree exists for %(base)s."""
141
179
def __init__(self, base):
142
180
BzrNewError.__init__(self)
146
184
class NotLocalUrl(BzrNewError):
147
"""%s(url) is not a local path."""
185
"""%(url)s is not a local path."""
149
187
def __init__(self, url):
150
188
BzrNewError.__init__(self)
154
class BzrCommandError(BzrError):
155
# Error from malformed user command
156
# This is being misused as a generic exception
157
# pleae subclass. RBC 20051030
192
class BzrCommandError(BzrNewError):
193
"""Error from user command"""
197
# Error from malformed user command; please avoid raising this as a
198
# generic exception not caused by user input.
159
200
# I think it's a waste of effort to differentiate between errors that
160
201
# are not intended to be caught anyway. UI code need not subclass
161
202
# BzrCommandError, and non-UI code should not throw a subclass of
162
203
# BzrCommandError. ADHB 20051211
204
def __init__(self, msg):
205
# Object.__str__() must return a real string
206
# returning a Unicode string is a python error.
207
if isinstance(msg, unicode):
208
self.msg = msg.encode('utf8')
163
212
def __str__(self):
167
216
class BzrOptionError(BzrCommandError):
168
"""Some missing or otherwise incorrect option was supplied."""
217
"""Error in command line options"""
171
class StrictCommitFailed(Exception):
172
"""Commit refused because there are unknowns in the tree."""
220
class StrictCommitFailed(BzrNewError):
221
"""Commit refused because there are unknown files in the tree"""
224
# XXX: Should be unified with TransportError; they seem to represent the
175
226
class PathError(BzrNewError):
176
227
"""Generic path error: %(path)r%(extra)s)"""
204
255
"""Permission denied: %(path)r%(extra)s"""
258
class InvalidURL(PathError):
259
"""Invalid url supplied to transport: %(path)r%(extra)s"""
262
class InvalidURLJoin(PathError):
263
"""Invalid URL join request: %(args)s%(extra)s"""
265
def __init__(self, msg, base, args):
266
PathError.__init__(self, base, msg)
268
self.args.extend(args)
271
class UnsupportedProtocol(PathError):
272
"""Unsupported protocol for url "%(path)s"%(extra)s"""
274
def __init__(self, url, extra):
275
PathError.__init__(self, url, extra=extra)
207
278
class PathNotChild(BzrNewError):
208
279
"""Path %(path)r is not a child of path %(base)r%(extra)s"""
281
is_user_error = False
209
283
def __init__(self, path, base, extra=None):
210
284
BzrNewError.__init__(self)
293
class InvalidNormalization(PathError):
294
"""Path %(path)r is not unicode normalized"""
297
# TODO: This is given a URL; we try to unescape it but doing that from inside
298
# the exception object is a bit undesirable.
299
# TODO: Probably this behavior of should be a common superclass
219
300
class NotBranchError(PathError):
220
301
"""Not a branch: %(path)s"""
303
def __init__(self, path):
304
import bzrlib.urlutils as urlutils
305
self.path = urlutils.unescape_for_display(path, 'ascii')
223
308
class AlreadyBranchError(PathError):
224
"""Already a branch: %(path)s. Use `bzr checkout` to build a working tree."""
309
"""Already a branch: %(path)s."""
312
class BranchExistsWithoutWorkingTree(PathError):
313
"""Directory contains a branch, but no working tree \
314
(use bzr checkout if you wish to build a working tree): %(path)s"""
317
class AtomicFileAlreadyClosed(PathError):
318
"""'%(function)s' called on an AtomicFile after it was closed: %(path)s"""
320
def __init__(self, path, function):
321
PathError.__init__(self, path=path, extra=None)
322
self.function = function
325
class InaccessibleParent(PathError):
326
"""Parent not accessible given base %(base)s and relative path %(path)s"""
328
def __init__(self, path, base):
329
PathError.__init__(self, path)
227
333
class NoRepositoryPresent(BzrNewError):
228
"""Not repository present: %(path)r"""
334
"""No repository present: %(path)r"""
229
335
def __init__(self, bzrdir):
230
336
BzrNewError.__init__(self)
231
337
self.path = bzrdir.transport.clone('..').base
244
class UnsupportedFormatError(BzrError):
245
"""Specified path is a bzr branch that we recognize but cannot read."""
247
return 'unsupported branch format: %s' % self.args[0]
250
class UnknownFormatError(BzrError):
251
"""Specified path is a bzr branch whose format we do not recognize."""
253
return 'unknown branch format: %s' % self.args[0]
350
class UnsupportedFormatError(BzrNewError):
351
"""Unsupported branch format: %(format)s"""
354
class UnknownFormatError(BzrNewError):
355
"""Unknown branch format: %(format)r"""
256
358
class IncompatibleFormat(BzrNewError):
280
382
self.paths_as_string = ' '.join([quotefn(p) for p in paths])
283
class BadFileKindError(BzrError):
284
"""Specified file is of a kind that cannot be added.
286
(For example a symlink or device file.)"""
289
class ForbiddenFileError(BzrError):
290
"""Cannot operate on a file because it is a control file."""
385
class PathsDoNotExist(BzrNewError):
386
"""Path(s) do not exist: %(paths_as_string)s"""
388
# used when reporting that paths are neither versioned nor in the working
391
def __init__(self, paths):
393
from bzrlib.osutils import quotefn
394
BzrNewError.__init__(self)
396
self.paths_as_string = ' '.join([quotefn(p) for p in paths])
399
class BadFileKindError(BzrNewError):
400
"""Cannot operate on %(filename)s of unsupported kind %(kind)s"""
403
class ForbiddenControlFileError(BzrNewError):
404
"""Cannot operate on %(filename)s because it is a control file"""
293
407
class LockError(BzrNewError):
392
509
"""Commit refused because there are unknowns in the tree."""
395
class NoSuchRevision(BzrError):
512
class NoSuchRevision(BzrNewError):
513
"""Branch %(branch)s has no revision %(revision)s"""
515
is_user_error = False
396
517
def __init__(self, branch, revision):
397
518
self.branch = branch
398
519
self.revision = revision
399
msg = "Branch %s has no revision %s" % (branch, revision)
400
BzrError.__init__(self, msg)
403
522
class HistoryMissing(BzrError):
408
527
% (branch, object_type, object_id))
411
class DivergedBranches(BzrError):
530
class DivergedBranches(BzrNewError):
531
"These branches have diverged. Use the merge command to reconcile them."""
413
535
def __init__(self, branch1, branch2):
414
BzrError.__init__(self, "These branches have diverged. Try merge.")
415
536
self.branch1 = branch1
416
537
self.branch2 = branch2
419
class UnrelatedBranches(BzrCommandError):
421
msg = "Branches have no common ancestor, and no base revision"\
423
BzrCommandError.__init__(self, msg)
426
class NoCommonAncestor(BzrError):
540
class UnrelatedBranches(BzrNewError):
541
"Branches have no common ancestor, and no merge base revision was specified."
546
class NoCommonAncestor(BzrNewError):
547
"Revisions have no common ancestor: %(revision_a)s %(revision_b)s"
427
549
def __init__(self, revision_a, revision_b):
428
msg = "Revisions have no common ancestor: %s %s." \
429
% (revision_a, revision_b)
430
BzrError.__init__(self, msg)
550
self.revision_a = revision_a
551
self.revision_b = revision_b
433
554
class NoCommonRoot(BzrError):
458
579
def __init__(self, bases):
459
580
warn("BzrError AmbiguousBase has been deprecated as of bzrlib 0.8.",
460
581
DeprecationWarning)
461
msg = "The correct base is unclear, becase %s are all equally close" %\
582
msg = "The correct base is unclear, because %s are all equally close" %\
463
584
BzrError.__init__(self, msg)
464
585
self.bases = bases
626
747
self.format = format
629
class TransportError(BzrError):
630
"""All errors thrown by Transport implementations should derive
750
class TransportError(BzrNewError):
751
"""Transport error: %(msg)s %(orig_error)s"""
633
753
def __init__(self, msg=None, orig_error=None):
634
754
if msg is None and orig_error is not None:
635
755
msg = str(orig_error)
636
BzrError.__init__(self, msg)
756
if orig_error is None:
638
761
self.orig_error = orig_error
762
BzrNewError.__init__(self)
641
765
# A set of semi-meaningful errors which can be thrown
642
766
class TransportNotPossible(TransportError):
643
"""This is for transports where a specific function is explicitly not
644
possible. Such as pushing files to an HTTP server.
767
"""Transport operation not possible: %(msg)s %(orig_error)%"""
649
770
class ConnectionError(TransportError):
650
"""A connection problem prevents file retrieval.
651
This does not indicate whether the file exists or not; it indicates that a
652
precondition for requesting the file was not met.
654
def __init__(self, msg=None, orig_error=None):
655
TransportError.__init__(self, msg=msg, orig_error=orig_error)
771
"""Connection error: %(msg)s %(orig_error)s"""
658
774
class ConnectionReset(TransportError):
659
"""The connection has been closed."""
775
"""Connection closed: %(msg)s %(orig_error)s"""
778
class InvalidRange(TransportError):
779
"""Invalid range access."""
781
def __init__(self, path, offset):
782
TransportError.__init__(self, ("Invalid range access in %s at %d"
786
class InvalidHttpResponse(TransportError):
787
"""Invalid http response for %(path)s: %(msg)s"""
789
def __init__(self, path, msg, orig_error=None):
791
TransportError.__init__(self, msg, orig_error=orig_error)
794
class InvalidHttpRange(InvalidHttpResponse):
795
"""Invalid http range "%(range)s" for %(path)s: %(msg)s"""
797
def __init__(self, path, range, msg):
799
InvalidHttpResponse.__init__(self, path, msg)
802
class InvalidHttpContentType(InvalidHttpResponse):
803
"""Invalid http Content-type "%(ctype)s" for %(path)s: %(msg)s"""
805
def __init__(self, path, ctype, msg):
807
InvalidHttpResponse.__init__(self, path, msg)
663
810
class ConflictsInTree(BzrError):
864
class NoBundleFound(BzrNewError):
865
"""No bundle was found in %(filename)s"""
866
def __init__(self, filename):
867
BzrNewError.__init__(self)
868
self.filename = filename
871
class BundleNotSupported(BzrNewError):
872
"""Unable to handle bundle version %(version)s: %(msg)s"""
873
def __init__(self, version, msg):
874
BzrNewError.__init__(self)
875
self.version = version
717
879
class MissingText(BzrNewError):
718
880
"""Branch %(base)s is missing revision %(text_revision)s of %(file_id)s"""
764
926
"""Parameter $(param)s is required but not present."""
929
class BzrBadParameterUnicode(BzrBadParameter):
930
"""Parameter %(param)s is unicode but only byte-strings are permitted."""
933
class BzrBadParameterContainsNewline(BzrBadParameter):
934
"""Parameter %(param)s contains a newline."""
767
937
class DependencyNotPresent(BzrNewError):
768
938
"""Unable to import library "%(library)s": %(error)s"""
851
1028
"""A nested progress bar was not 'finished' correctly."""
1031
class InvalidProgressBarType(BzrNewError):
1032
"""Environment variable BZR_PROGRESS_BAR='%(bar_type)s is not a supported type
1033
Select one of: %(valid_types)s"""
1035
def __init__(self, bar_type, valid_types):
1036
BzrNewError.__init__(self, bar_type=bar_type, valid_types=valid_types)
854
1039
class UnsupportedOperation(BzrNewError):
855
1040
"""The method %(mname)s is not supported on objects of type %(tname)s."""
856
1041
def __init__(self, method, method_self):
857
1042
self.method = method
858
1043
self.mname = method.__name__
859
1044
self.tname = type(method_self).__name__
1047
class BinaryFile(BzrNewError):
1048
"""File is binary but should be text."""
1051
class IllegalPath(BzrNewError):
1052
"""The path %(path)s is not permitted on this platform"""
1054
def __init__(self, path):
1055
BzrNewError.__init__(self)
1059
class TestamentMismatch(BzrNewError):
1060
"""Testament did not match expected value.
1061
For revision_id {%(revision_id)s}, expected {%(expected)s}, measured
1064
def __init__(self, revision_id, expected, measured):
1065
self.revision_id = revision_id
1066
self.expected = expected
1067
self.measured = measured
1070
class NotABundle(BzrNewError):
1071
"""Not a bzr revision-bundle: %(text)r"""
1073
def __init__(self, text):
1074
BzrNewError.__init__(self)
1078
class BadBundle(BzrNewError):
1079
"""Bad bzr revision-bundle: %(text)r"""
1081
def __init__(self, text):
1082
BzrNewError.__init__(self)
1086
class MalformedHeader(BadBundle):
1087
"""Malformed bzr revision-bundle header: %(text)r"""
1089
def __init__(self, text):
1090
BzrNewError.__init__(self)
1094
class MalformedPatches(BadBundle):
1095
"""Malformed patches in bzr revision-bundle: %(text)r"""
1097
def __init__(self, text):
1098
BzrNewError.__init__(self)
1102
class MalformedFooter(BadBundle):
1103
"""Malformed footer in bzr revision-bundle: %(text)r"""
1105
def __init__(self, text):
1106
BzrNewError.__init__(self)
1109
class UnsupportedEOLMarker(BadBundle):
1110
"""End of line marker was not \\n in bzr revision-bundle"""
1113
BzrNewError.__init__(self)