~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/errors.py

  • Committer: Aaron Bentley
  • Date: 2007-12-25 04:17:50 UTC
  • mto: This revision was merged to the branch mainline in revision 3160.
  • Revision ID: aaron.bentley@utoronto.ca-20071225041750-t6chr3pmgnebvqcz
Handle non-directory parent conflicts (abentley, #177390)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
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
93
93
            for key, value in kwds.items():
94
94
                setattr(self, key, value)
95
95
 
96
 
    def _format(self):
 
96
    def __str__(self):
97
97
        s = getattr(self, '_preformatted_string', None)
98
98
        if s is not None:
99
 
            # contains a preformatted message
100
 
            return s
 
99
            # contains a preformatted message; must be cast to plain str
 
100
            return str(s)
101
101
        try:
102
102
            fmt = self._get_format_string()
103
103
            if fmt:
108
108
                s = fmt % d
109
109
                # __str__() should always return a 'str' object
110
110
                # never a 'unicode' object.
 
111
                if isinstance(s, unicode):
 
112
                    return s.encode('utf8')
111
113
                return s
112
114
        except (AttributeError, TypeError, NameError, ValueError, KeyError), e:
113
115
            return 'Unprintable exception %s: dict=%r, fmt=%r, error=%r' \
116
118
                   getattr(self, '_fmt', None),
117
119
                   e)
118
120
 
119
 
    def __unicode__(self):
120
 
        u = self._format()
121
 
        if isinstance(u, str):
122
 
            # Try decoding the str using the default encoding.
123
 
            u = unicode(u)
124
 
        elif not isinstance(u, unicode):
125
 
            # Try to make a unicode object from it, because __unicode__ must
126
 
            # return a unicode object.
127
 
            u = unicode(u)
128
 
        return u
129
 
    
130
 
    def __str__(self):
131
 
        s = self._format()
132
 
        if isinstance(s, unicode):
133
 
            s = s.encode('utf8')
134
 
        else:
135
 
            # __str__ must return a str.
136
 
            s = str(s)
137
 
        return s
138
 
 
139
121
    def _get_format_string(self):
140
122
        """Return format string for this exception or None"""
141
123
        fmt = getattr(self, '_fmt', None)
153
135
               getattr(self, '_fmt', None),
154
136
               )
155
137
 
156
 
    def __eq__(self, other):
157
 
        if self.__class__ != other.__class__:
158
 
            return NotImplemented
159
 
        return self.__dict__ == other.__dict__
160
 
 
161
138
 
162
139
class InternalBzrError(BzrError):
163
140
    """Base class for errors that are internal in nature.
208
185
    _fmt = "The tree builder is already building a tree."
209
186
 
210
187
 
211
 
class BranchError(BzrError):
212
 
    """Base class for concrete 'errors about a branch'."""
213
 
 
214
 
    def __init__(self, branch):
215
 
        BzrError.__init__(self, branch=branch)
216
 
 
217
 
 
218
188
class BzrCheckError(InternalBzrError):
219
189
    
220
190
    _fmt = "Internal check failed: %(message)s"
297
267
        "record_entry_contents.")
298
268
 
299
269
 
300
 
class NoPublicBranch(BzrError):
301
 
 
302
 
    _fmt = 'There is no public branch set for "%(branch_url)s".'
303
 
 
304
 
    def __init__(self, branch):
305
 
        import bzrlib.urlutils as urlutils
306
 
        public_location = urlutils.unescape_for_display(branch.base, 'ascii')
307
 
        BzrError.__init__(self, branch_url=public_location)
308
 
 
309
 
 
310
270
class NoHelpTopic(BzrError):
311
271
 
312
272
    _fmt = ("No help could be found for '%(topic)s'. "
335
295
        BzrError.__init__(self, repository=repository, file_id=file_id)
336
296
 
337
297
 
338
 
class NotStacked(BranchError):
339
 
 
340
 
    _fmt = "The branch '%(branch)s' is not stacked."
341
 
 
342
 
 
343
298
class InventoryModified(InternalBzrError):
344
299
 
345
300
    _fmt = ("The current inventory for the tree %(tree)r has been modified,"
389
344
    # are not intended to be caught anyway.  UI code need not subclass
390
345
    # BzrCommandError, and non-UI code should not throw a subclass of
391
346
    # BzrCommandError.  ADHB 20051211
 
347
    def __init__(self, msg):
 
348
        # Object.__str__() must return a real string
 
349
        # returning a Unicode string is a python error.
 
350
        if isinstance(msg, unicode):
 
351
            self.msg = msg.encode('utf8')
 
352
        else:
 
353
            self.msg = msg
 
354
 
 
355
    def __str__(self):
 
356
        return self.msg
392
357
 
393
358
 
394
359
class NotWriteLocked(BzrError):
534
499
    _fmt = 'Directory not empty: "%(path)s"%(extra)s'
535
500
 
536
501
 
537
 
class HardLinkNotSupported(PathError):
538
 
 
539
 
    _fmt = 'Hard-linking "%(path)s" is not supported'
540
 
 
541
 
 
542
502
class ReadingCompleted(InternalBzrError):
543
503
    
544
504
    _fmt = ("The MediumRequest '%(request)s' has already had finish_reading "
566
526
 
567
527
class InvalidURLJoin(PathError):
568
528
 
569
 
    _fmt = "Invalid URL join request: %(reason)s: %(base)r + %(join_args)r"
570
 
 
571
 
    def __init__(self, reason, base, join_args):
572
 
        self.reason = reason
573
 
        self.base = base
574
 
        self.join_args = join_args
575
 
        PathError.__init__(self, base, reason)
576
 
 
577
 
 
578
 
class InvalidRebaseURLs(PathError):
579
 
 
580
 
    _fmt = "URLs differ by more than path: %(from_)r and %(to)r"
581
 
 
582
 
    def __init__(self, from_, to):
583
 
        self.from_ = from_
584
 
        self.to = to
585
 
        PathError.__init__(self, from_, 'URLs differ by more than path.')
586
 
 
587
 
 
588
 
class UnavailableRepresentation(InternalBzrError):
589
 
 
590
 
    _fmt = ("The encoding '%(wanted)s' is not available for key %(key)s which "
591
 
        "is encoded as '%(native)s'.")
592
 
 
593
 
    def __init__(self, key, wanted, native):
594
 
        InternalBzrError.__init__(self)
595
 
        self.wanted = wanted
596
 
        self.native = native
597
 
        self.key = key
 
529
    _fmt = 'Invalid URL join request: "%(args)s"%(extra)s'
 
530
 
 
531
    def __init__(self, msg, base, args):
 
532
        PathError.__init__(self, base, msg)
 
533
        self.args = [base] + list(args)
598
534
 
599
535
 
600
536
class UnknownHook(BzrError):
615
551
        PathError.__init__(self, url, extra=extra)
616
552
 
617
553
 
618
 
class UnstackableBranchFormat(BzrError):
619
 
 
620
 
    _fmt = ("The branch '%(url)s'(%(format)s) is not a stackable format. "
621
 
        "You will need to upgrade the branch to permit branch stacking.")
622
 
 
623
 
    def __init__(self, format, url):
624
 
        BzrError.__init__(self)
625
 
        self.format = format
626
 
        self.url = url
627
 
 
628
 
 
629
 
class UnstackableRepositoryFormat(BzrError):
630
 
 
631
 
    _fmt = ("The repository '%(url)s'(%(format)s) is not a stackable format. "
632
 
        "You will need to upgrade the repository to permit branch stacking.")
633
 
 
634
 
    def __init__(self, format, url):
635
 
        BzrError.__init__(self)
636
 
        self.format = format
637
 
        self.url = url
638
 
 
639
 
 
640
554
class ReadError(PathError):
641
555
    
642
556
    _fmt = """Error reading from %(path)r."""
755
669
 
756
670
class UnknownFormatError(BzrError):
757
671
    
758
 
    _fmt = "Unknown %(kind)s format: %(format)r"
759
 
 
760
 
    def __init__(self, format, kind='branch'):
761
 
        self.kind = kind
762
 
        self.format = format
 
672
    _fmt = "Unknown branch format: %(format)r"
763
673
 
764
674
 
765
675
class IncompatibleFormat(BzrError):
774
684
 
775
685
class IncompatibleRepositories(BzrError):
776
686
 
777
 
    _fmt = "%(target)s\n" \
778
 
            "is not compatible with\n" \
779
 
            "%(source)s\n" \
780
 
            "%(details)s"
 
687
    _fmt = "Repository %(target)s is not compatible with repository"\
 
688
        " %(source)s"
781
689
 
782
 
    def __init__(self, source, target, details=None):
783
 
        if details is None:
784
 
            details = "(no details)"
785
 
        BzrError.__init__(self, target=target, source=source, details=details)
 
690
    def __init__(self, source, target):
 
691
        BzrError.__init__(self, target=target, source=source)
786
692
 
787
693
 
788
694
class IncompatibleRevision(BzrError):
875
781
        BzrError.__init__(self, filename=filename, kind=kind)
876
782
 
877
783
 
878
 
class BadFilenameEncoding(BzrError):
879
 
 
880
 
    _fmt = ('Filename %(filename)r is not valid in your current filesystem'
881
 
            ' encoding %(fs_encoding)s')
882
 
 
883
 
    def __init__(self, filename, fs_encoding):
884
 
        BzrError.__init__(self)
885
 
        self.filename = filename
886
 
        self.fs_encoding = fs_encoding
887
 
 
888
 
 
889
784
class ForbiddenControlFileError(BzrError):
890
785
 
891
786
    _fmt = 'Cannot operate on "%(filename)s" because it is a control file'
944
839
        self.obj = obj
945
840
 
946
841
 
 
842
class ReadOnlyLockError(LockError):
 
843
 
 
844
    _fmt = "Cannot acquire write lock on %(fname)s. %(msg)s"
 
845
 
 
846
    @symbol_versioning.deprecated_method(symbol_versioning.zero_ninetytwo)
 
847
    def __init__(self, fname, msg):
 
848
        LockError.__init__(self, '')
 
849
        self.fname = fname
 
850
        self.msg = msg
 
851
 
 
852
 
947
853
class LockFailed(LockError):
948
854
 
949
855
    internal_error = False
1105
1011
        BzrError.__init__(self, branch=branch, revision=revision)
1106
1012
 
1107
1013
 
 
1014
# zero_ninetyone: this exception is no longer raised and should be removed
 
1015
class NotLeftParentDescendant(InternalBzrError):
 
1016
 
 
1017
    _fmt = ("Revision %(old_revision)s is not the left parent of"
 
1018
            " %(new_revision)s, but branch %(branch_location)s expects this")
 
1019
 
 
1020
    def __init__(self, branch, old_revision, new_revision):
 
1021
        BzrError.__init__(self, branch_location=branch.base,
 
1022
                          old_revision=old_revision,
 
1023
                          new_revision=new_revision)
 
1024
 
 
1025
 
1108
1026
class RangeInChangeOption(BzrError):
1109
1027
 
1110
1028
    _fmt = "Option --change does not accept revision ranges"
1236
1154
        self.bases = bases
1237
1155
 
1238
1156
 
1239
 
class NoCommits(BranchError):
 
1157
class NoCommits(BzrError):
1240
1158
 
1241
1159
    _fmt = "Branch %(branch)s has no commits."
1242
1160
 
 
1161
    def __init__(self, branch):
 
1162
        BzrError.__init__(self, branch=branch)
 
1163
 
1243
1164
 
1244
1165
class UnlistableStore(BzrError):
1245
1166
 
1503
1424
        self.details = details
1504
1425
 
1505
1426
 
1506
 
class UnexpectedProtocolVersionMarker(TransportError):
1507
 
 
1508
 
    _fmt = "Received bad protocol version marker: %(marker)r"
1509
 
 
1510
 
    def __init__(self, marker):
1511
 
        self.marker = marker
1512
 
 
1513
 
 
1514
 
class UnknownSmartMethod(InternalBzrError):
1515
 
 
1516
 
    _fmt = "The server does not recognise the '%(verb)s' request."
1517
 
 
1518
 
    def __init__(self, verb):
1519
 
        self.verb = verb
1520
 
 
1521
 
 
1522
 
class SmartMessageHandlerError(InternalBzrError):
1523
 
 
1524
 
    _fmt = "The message handler raised an exception: %(exc_value)s."
1525
 
 
1526
 
    def __init__(self, exc_info):
1527
 
        self.exc_type, self.exc_value, self.tb = exc_info
1528
 
        
1529
 
 
1530
1427
# A set of semi-meaningful errors which can be thrown
1531
1428
class TransportNotPossible(TransportError):
1532
1429
 
1973
1870
        BzrError.__init__(self, path)
1974
1871
 
1975
1872
 
1976
 
class ExecutableMissing(BzrError):
1977
 
 
1978
 
    _fmt = "%(exe_name)s could not be found on this machine"
1979
 
 
1980
 
    def __init__(self, exe_name):
1981
 
        BzrError.__init__(self, exe_name=exe_name)
1982
 
 
1983
 
 
1984
1873
class NoDiff(BzrError):
1985
1874
 
1986
1875
    _fmt = "Diff is not installed on this machine: %(msg)s"
2074
1963
    _fmt = "Format error in conflict listings"
2075
1964
 
2076
1965
 
2077
 
class CorruptDirstate(BzrError):
2078
 
 
2079
 
    _fmt = ("Inconsistency in dirstate file %(dirstate_path)s.\n"
2080
 
            "Error: %(description)s")
2081
 
 
2082
 
    def __init__(self, dirstate_path, description):
2083
 
        BzrError.__init__(self)
2084
 
        self.dirstate_path = dirstate_path
2085
 
        self.description = description
2086
 
 
2087
 
 
2088
1966
class CorruptRepository(BzrError):
2089
1967
 
2090
1968
    _fmt = ("An error has been detected in the repository %(repo_path)s.\n"
2095
1973
        self.repo_path = repo.bzrdir.root_transport.base
2096
1974
 
2097
1975
 
2098
 
class InconsistentDelta(BzrError):
2099
 
    """Used when we get a delta that is not valid."""
2100
 
 
2101
 
    _fmt = ("An inconsistent delta was supplied involving %(path)r,"
2102
 
            " %(file_id)r\nreason: %(reason)s")
2103
 
 
2104
 
    def __init__(self, path, file_id, reason):
2105
 
        BzrError.__init__(self)
2106
 
        self.path = path
2107
 
        self.file_id = file_id
2108
 
        self.reason = reason
2109
 
 
2110
 
 
2111
1976
class UpgradeRequired(BzrError):
2112
1977
 
2113
1978
    _fmt = "To use this feature you must upgrade your branch at %(path)s."
2117
1982
        self.path = path
2118
1983
 
2119
1984
 
2120
 
class RepositoryUpgradeRequired(UpgradeRequired):
2121
 
 
2122
 
    _fmt = "To use this feature you must upgrade your repository at %(path)s."
2123
 
 
2124
 
 
2125
1985
class LocalRequiresBoundBranch(BzrError):
2126
1986
 
2127
1987
    _fmt = "Cannot perform local-only commits on unbound branches."
2271
2131
 
2272
2132
    _fmt = "No smart server available at %(url)s"
2273
2133
 
2274
 
    @symbol_versioning.deprecated_method(symbol_versioning.one_four)
2275
2134
    def __init__(self, url):
2276
2135
        self.url = url
2277
2136
 
2291
2150
            " Please set BZR_SSH environment variable.")
2292
2151
 
2293
2152
 
2294
 
class GhostRevisionsHaveNoRevno(BzrError):
2295
 
    """When searching for revnos, if we encounter a ghost, we are stuck"""
2296
 
 
2297
 
    _fmt = ("Could not determine revno for {%(revision_id)s} because"
2298
 
            " its ancestry shows a ghost at {%(ghost_revision_id)s}")
2299
 
 
2300
 
    def __init__(self, revision_id, ghost_revision_id):
2301
 
        self.revision_id = revision_id
2302
 
        self.ghost_revision_id = ghost_revision_id
2303
 
 
2304
 
        
2305
2153
class GhostRevisionUnusableHere(BzrError):
2306
2154
 
2307
2155
    _fmt = "Ghost revision {%(revision_id)s} cannot be used here."
2385
2233
        self.patch_type = patch_type
2386
2234
 
2387
2235
 
2388
 
class TargetNotBranch(BzrError):
2389
 
    """A merge directive's target branch is required, but isn't a branch"""
2390
 
 
2391
 
    _fmt = ("Your branch does not have all of the revisions required in "
2392
 
            "order to merge this merge directive and the target "
2393
 
            "location specified in the merge directive is not a branch: "
2394
 
            "%(location)s.")
2395
 
 
2396
 
    def __init__(self, location):
2397
 
        BzrError.__init__(self)
2398
 
        self.location = location
2399
 
 
2400
 
 
2401
2236
class UnsupportedInventoryKind(BzrError):
2402
2237
    
2403
2238
    _fmt = """Unsupported entry kind %(kind)s"""
2446
2281
class TagsNotSupported(BzrError):
2447
2282
 
2448
2283
    _fmt = ("Tags not supported by %(branch)s;"
2449
 
            " you may be able to use bzr upgrade.")
 
2284
            " you may be able to use bzr upgrade --dirstate-tags.")
2450
2285
 
2451
2286
    def __init__(self, branch):
2452
2287
        self.branch = branch
2497
2332
        self.response_tuple = response_tuple
2498
2333
 
2499
2334
 
2500
 
class ErrorFromSmartServer(BzrError):
2501
 
 
2502
 
    _fmt = "Error received from smart server: %(error_tuple)r"
2503
 
 
2504
 
    internal_error = True
2505
 
 
2506
 
    def __init__(self, error_tuple):
2507
 
        self.error_tuple = error_tuple
2508
 
        try:
2509
 
            self.error_verb = error_tuple[0]
2510
 
        except IndexError:
2511
 
            self.error_verb = None
2512
 
        self.error_args = error_tuple[1:]
2513
 
 
2514
 
 
2515
2335
class ContainerError(BzrError):
2516
2336
    """Base class of container errors."""
2517
2337
 
2633
2453
        BzrError.__init__(self, bzrdir=bzrdir, display_url=display_url)
2634
2454
 
2635
2455
 
2636
 
class UnsyncedBranches(BzrDirError):
2637
 
 
2638
 
    _fmt = ("'%(display_url)s' is not in sync with %(target_url)s.  See"
2639
 
            " bzr help sync-for-reconfigure.")
2640
 
 
2641
 
    def __init__(self, bzrdir, target_branch):
2642
 
        BzrDirError.__init__(self, bzrdir)
2643
 
        import bzrlib.urlutils as urlutils
2644
 
        self.target_url = urlutils.unescape_for_display(target_branch.base,
2645
 
                                                        'ascii')
2646
 
 
2647
 
 
2648
2456
class AlreadyBranch(BzrDirError):
2649
2457
 
2650
2458
    _fmt = "'%(display_url)s' is already a branch."
2665
2473
    _fmt = "'%(display_url)s' is already a lightweight checkout."
2666
2474
 
2667
2475
 
2668
 
class AlreadyUsingShared(BzrDirError):
2669
 
 
2670
 
    _fmt = "'%(display_url)s' is already using a shared repository."
2671
 
 
2672
 
 
2673
 
class AlreadyStandalone(BzrDirError):
2674
 
 
2675
 
    _fmt = "'%(display_url)s' is already standalone."
2676
 
 
2677
 
 
2678
2476
class ReconfigurationNotSupported(BzrDirError):
2679
2477
 
2680
2478
    _fmt = "Requested reconfiguration of '%(display_url)s' is not supported."
2704
2502
        self.name = name
2705
2503
 
2706
2504
 
2707
 
class NoTemplate(BzrError):
2708
 
 
2709
 
    _fmt = 'No template specified.'
2710
 
 
2711
 
 
2712
2505
class UnableCreateSymlink(BzrError):
2713
2506
 
2714
2507
    _fmt = 'Unable to create symlink %(path_str)son this platform'
2722
2515
                path_str = repr(path)
2723
2516
            path_str += ' '
2724
2517
        self.path_str = path_str
2725
 
 
2726
 
 
2727
 
class UnsupportedTimezoneFormat(BzrError):
2728
 
 
2729
 
    _fmt = ('Unsupported timezone format "%(timezone)s", '
2730
 
            'options are "utc", "original", "local".')
2731
 
 
2732
 
    def __init__(self, timezone):
2733
 
        self.timezone = timezone
2734
 
 
2735
 
 
2736
 
class CommandAvailableInPlugin(StandardError):
2737
 
    
2738
 
    internal_error = False
2739
 
 
2740
 
    def __init__(self, cmd_name, plugin_metadata, provider):
2741
 
        
2742
 
        self.plugin_metadata = plugin_metadata
2743
 
        self.cmd_name = cmd_name
2744
 
        self.provider = provider
2745
 
 
2746
 
    def __str__(self):
2747
 
 
2748
 
        _fmt = ('"%s" is not a standard bzr command. \n' 
2749
 
                'However, the following official plugin provides this command: %s\n'
2750
 
                'You can install it by going to: %s'
2751
 
                % (self.cmd_name, self.plugin_metadata['name'], 
2752
 
                    self.plugin_metadata['url']))
2753
 
 
2754
 
        return _fmt
2755
 
 
2756
 
 
2757
 
class NoPluginAvailable(BzrError):
2758
 
    pass    
2759
 
 
2760
 
 
2761
 
class NotATerminal(BzrError):
2762
 
 
2763
 
    _fmt = 'Unable to ask for a password without real terminal.'
2764
 
 
2765
 
 
2766
 
class UnableEncodePath(BzrError):
2767
 
 
2768
 
    _fmt = ('Unable to encode %(kind)s path %(path)r in '
2769
 
            'user encoding %(user_encoding)s')
2770
 
 
2771
 
    def __init__(self, path, kind):
2772
 
        self.path = path
2773
 
        self.kind = kind
2774
 
        self.user_encoding = osutils.get_user_encoding()
2775
 
 
2776
 
 
2777
 
class NoSuchAlias(BzrError):
2778
 
 
2779
 
    _fmt = ('The alias "%(alias_name)s" does not exist.')
2780
 
 
2781
 
    def __init__(self, alias_name):
2782
 
        BzrError.__init__(self, alias_name=alias_name)
2783
 
 
2784
 
 
2785
 
class DirectoryLookupFailure(BzrError):
2786
 
    """Base type for lookup errors."""
2787
 
 
2788
 
    pass
2789
 
 
2790
 
 
2791
 
class InvalidLocationAlias(DirectoryLookupFailure):
2792
 
 
2793
 
    _fmt = '"%(alias_name)s" is not a valid location alias.'
2794
 
 
2795
 
    def __init__(self, alias_name):
2796
 
        DirectoryLookupFailure.__init__(self, alias_name=alias_name)
2797
 
 
2798
 
 
2799
 
class UnsetLocationAlias(DirectoryLookupFailure):
2800
 
 
2801
 
    _fmt = 'No %(alias_name)s location assigned.'
2802
 
 
2803
 
    def __init__(self, alias_name):
2804
 
        DirectoryLookupFailure.__init__(self, alias_name=alias_name[1:])
2805
 
 
2806
 
 
2807
 
class CannotBindAddress(BzrError):
2808
 
 
2809
 
    _fmt = 'Cannot bind address "%(host)s:%(port)i": %(orig_error)s.'
2810
 
 
2811
 
    def __init__(self, host, port, orig_error):
2812
 
        BzrError.__init__(self, host=host, port=port,
2813
 
            orig_error=orig_error[1])
2814
 
 
2815
 
 
2816
 
class UnknownRules(BzrError):
2817
 
 
2818
 
    _fmt = ('Unknown rules detected: %(unknowns_str)s.')
2819
 
 
2820
 
    def __init__(self, unknowns):
2821
 
        BzrError.__init__(self, unknowns_str=", ".join(unknowns))
2822
 
 
2823
 
 
2824
 
class HookFailed(BzrError):
2825
 
    """Raised when a pre_change_branch_tip hook function fails anything other
2826
 
    than TipChangeRejected.
2827
 
    """
2828
 
 
2829
 
    _fmt = ("Hook '%(hook_name)s' during %(hook_stage)s failed:\n"
2830
 
            "%(traceback_text)s%(exc_value)s")
2831
 
 
2832
 
    def __init__(self, hook_stage, hook_name, exc_info):
2833
 
        import traceback
2834
 
        self.hook_stage = hook_stage
2835
 
        self.hook_name = hook_name
2836
 
        self.exc_info = exc_info
2837
 
        self.exc_type = exc_info[0]
2838
 
        self.exc_value = exc_info[1]
2839
 
        self.exc_tb = exc_info[2]
2840
 
        self.traceback_text = ''.join(traceback.format_tb(self.exc_tb))
2841
 
 
2842
 
 
2843
 
class TipChangeRejected(BzrError):
2844
 
    """A pre_change_branch_tip hook function may raise this to cleanly and
2845
 
    explicitly abort a change to a branch tip.
2846
 
    """
2847
 
    
2848
 
    _fmt = u"Tip change rejected: %(msg)s"
2849
 
 
2850
 
    def __init__(self, msg):
2851
 
        self.msg = msg
2852