f2d5d889a607a5d95725c68e649dbf4c0458b230
[jelmer/python-fastimport.git] / fastimport / errors.py
1 # Copyright (C) 2008 Canonical Ltd
2 #
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17 """Exception classes for fastimport"""
18
19 # Prefix to messages to show location information
20 _LOCATION_FMT = "line %(lineno)d: "
21
22 # ImportError is heavily based on BzrError
23
24 class ImportError(StandardError):
25     """The base exception class for all import processing exceptions."""
26
27     _fmt = "Unknown Import Error"
28
29     def __init__(self, msg=None, **kwds):
30         StandardError.__init__(self)
31         if msg is not None:
32             self._preformatted_string = msg
33         else:
34             self._preformatted_string = None
35             for key, value in kwds.items():
36                 setattr(self, key, value)
37
38     def _format(self):
39         s = getattr(self, '_preformatted_string', None)
40         if s is not None:
41             # contains a preformatted message
42             return s
43         try:
44             fmt = self._fmt
45             if fmt:
46                 d = dict(self.__dict__)
47                 s = fmt % d
48                 # __str__() should always return a 'str' object
49                 # never a 'unicode' object.
50                 return s
51         except (AttributeError, TypeError, NameError, ValueError, KeyError), e:
52             return 'Unprintable exception %s: dict=%r, fmt=%r, error=%r' \
53                 % (self.__class__.__name__,
54                    self.__dict__,
55                    getattr(self, '_fmt', None),
56                    e)
57
58     def __unicode__(self):
59         u = self._format()
60         if isinstance(u, str):
61             # Try decoding the str using the default encoding.
62             u = unicode(u)
63         elif not isinstance(u, unicode):
64             # Try to make a unicode object from it, because __unicode__ must
65             # return a unicode object.
66             u = unicode(u)
67         return u
68
69     def __str__(self):
70         s = self._format()
71         if isinstance(s, unicode):
72             s = s.encode('utf8')
73         else:
74             # __str__ must return a str.
75             s = str(s)
76         return s
77
78     def __repr__(self):
79         return '%s(%s)' % (self.__class__.__name__, str(self))
80
81     def __eq__(self, other):
82         if self.__class__ is not other.__class__:
83             return NotImplemented
84         return self.__dict__ == other.__dict__
85
86
87 class ParsingError(ImportError):
88     """The base exception class for all import processing exceptions."""
89
90     _fmt = _LOCATION_FMT + "Unknown Import Parsing Error"
91
92     def __init__(self, lineno):
93         ImportError.__init__(self)
94         self.lineno = lineno
95
96
97 class MissingBytes(ParsingError):
98     """Raised when EOF encountered while expecting to find more bytes."""
99
100     _fmt = (_LOCATION_FMT + "Unexpected EOF - expected %(expected)d bytes,"
101         " found %(found)d")
102
103     def __init__(self, lineno, expected, found):
104         ParsingError.__init__(self, lineno)
105         self.expected = expected
106         self.found = found
107
108
109 class MissingTerminator(ParsingError):
110     """Raised when EOF encountered while expecting to find a terminator."""
111
112     _fmt = (_LOCATION_FMT +
113         "Unexpected EOF - expected '%(terminator)s' terminator")
114
115     def __init__(self, lineno, terminator):
116         ParsingError.__init__(self, lineno)
117         self.terminator = terminator
118
119
120 class InvalidCommand(ParsingError):
121     """Raised when an unknown command found."""
122
123     _fmt = (_LOCATION_FMT + "Invalid command '%(cmd)s'")
124
125     def __init__(self, lineno, cmd):
126         ParsingError.__init__(self, lineno)
127         self.cmd = cmd
128
129
130 class MissingSection(ParsingError):
131     """Raised when a section is required in a command but not present."""
132
133     _fmt = (_LOCATION_FMT + "Command %(cmd)s is missing section %(section)s")
134
135     def __init__(self, lineno, cmd, section):
136         ParsingError.__init__(self, lineno)
137         self.cmd = cmd
138         self.section = section
139
140
141 class BadFormat(ParsingError):
142     """Raised when a section is formatted incorrectly."""
143
144     _fmt = (_LOCATION_FMT + "Bad format for section %(section)s in "
145         "command %(cmd)s: found '%(text)s'")
146
147     def __init__(self, lineno, cmd, section, text):
148         ParsingError.__init__(self, lineno)
149         self.cmd = cmd
150         self.section = section
151         self.text = text
152
153
154 class InvalidTimezone(ParsingError):
155     """Raised when converting a string timezone to a seconds offset."""
156
157     _fmt = (_LOCATION_FMT +
158         "Timezone %(timezone)r could not be converted.%(reason)s")
159
160     def __init__(self, lineno, timezone, reason=None):
161         ParsingError.__init__(self, lineno)
162         self.timezone = timezone
163         if reason:
164             self.reason = ' ' + reason
165         else:
166             self.reason = ''
167
168
169 class UnknownDateFormat(ImportError):
170     """Raised when an unknown date format is given."""
171
172     _fmt = ("Unknown date format '%(format)s'")
173
174     def __init__(self, format):
175         ImportError.__init__(self)
176         self.format = format
177
178
179 class MissingHandler(ImportError):
180     """Raised when a processor can't handle a command."""
181
182     _fmt = ("Missing handler for command %(cmd)s")
183
184     def __init__(self, cmd):
185         ImportError.__init__(self)
186         self.cmd = cmd
187
188
189 class UnknownParameter(ImportError):
190     """Raised when an unknown parameter is passed to a processor."""
191
192     _fmt = ("Unknown parameter - '%(param)s' not in %(knowns)s")
193
194     def __init__(self, param, knowns):
195         ImportError.__init__(self)
196         self.param = param
197         self.knowns = knowns
198
199
200 class BadRepositorySize(ImportError):
201     """Raised when the repository has an incorrect number of revisions."""
202
203     _fmt = ("Bad repository size - %(found)d revisions found, "
204         "%(expected)d expected")
205
206     def __init__(self, expected, found):
207         ImportError.__init__(self)
208         self.expected = expected
209         self.found = found
210
211
212 class BadRestart(ImportError):
213     """Raised when the import stream and id-map do not match up."""
214
215     _fmt = ("Bad restart - attempted to skip commit %(commit_id)s "
216         "but matching revision-id is unknown")
217
218     def __init__(self, commit_id):
219         ImportError.__init__(self)
220         self.commit_id = commit_id
221
222
223 class UnknownFeature(ImportError):
224     """Raised when an unknown feature is given in the input stream."""
225
226     _fmt = ("Unknown feature '%(feature)s' - try a later importer or "
227         "an earlier data format")
228
229     def __init__(self, feature):
230         ImportError.__init__(self)
231         self.feature = feature