blob: 504368752ccd0aec7fe8e64dde9222405ce3c1b3 [file] [log] [blame]
Guido van Rossum3d209861997-12-09 16:10:31 +00001"""Configuration file parser.
2
3A setup file consists of sections, lead by a "[section]" header,
4and followed by "name: value" entries, with continuations and such in
Barry Warsawbfa3f6b1998-07-01 20:41:12 +00005the style of RFC 822.
Guido van Rossum3d209861997-12-09 16:10:31 +00006
Barry Warsawbfa3f6b1998-07-01 20:41:12 +00007The option values can contain format strings which refer to other values in
8the same section, or values in a special [DEFAULT] section.
9
Guido van Rossum3d209861997-12-09 16:10:31 +000010For example:
11
12 something: %(dir)s/whatever
13
14would resolve the "%(dir)s" to the value of dir. All reference
15expansions are done late, on demand.
16
17Intrinsic defaults can be specified by passing them into the
18ConfigParser constructor as a dictionary.
19
20class:
21
22ConfigParser -- responsible for for parsing a list of
23 configuration files, and managing the parsed database.
24
25 methods:
26
Barry Warsawf09f6a51999-01-26 22:01:37 +000027 __init__(defaults=None)
28 create the parser and specify a dictionary of intrinsic defaults. The
29 keys must be strings, the values must be appropriate for %()s string
30 interpolation. Note that `__name__' is always an intrinsic default;
31 it's value is the section's name.
Guido van Rossum3d209861997-12-09 16:10:31 +000032
Barry Warsawf09f6a51999-01-26 22:01:37 +000033 sections()
34 return all the configuration section names, sans DEFAULT
Guido van Rossum3d209861997-12-09 16:10:31 +000035
Guido van Rossuma5a24b71999-10-04 19:58:22 +000036 has_section(section)
37 return whether the given section exists
38
Eric S. Raymond649685a2000-07-14 14:28:22 +000039 has_option(section, option)
40 return whether the given option exists in the given section
41
Barry Warsawf09f6a51999-01-26 22:01:37 +000042 options(section)
43 return list of configuration options for the named section
Guido van Rossum3d209861997-12-09 16:10:31 +000044
Guido van Rossuma5a24b71999-10-04 19:58:22 +000045 has_option(section, option)
46 return whether the given section has the given option
47
Guido van Rossumc0780ac1999-01-30 04:35:47 +000048 read(filenames)
Guido van Rossum6a8d84b1999-10-04 18:57:27 +000049 read and parse the list of named configuration files, given by
50 name. A single filename is also allowed. Non-existing files
51 are ignored.
52
53 readfp(fp, filename=None)
54 read and parse one configuration file, given as a file object.
55 The filename defaults to fp.name; it is only used in error
Barry Warsaw25394511999-10-12 16:12:48 +000056 messages (if fp has no `name' attribute, the string `<???>' is used).
Guido van Rossum3d209861997-12-09 16:10:31 +000057
Barry Warsawf09f6a51999-01-26 22:01:37 +000058 get(section, option, raw=0, vars=None)
59 return a string value for the named option. All % interpolations are
60 expanded in the return values, based on the defaults passed into the
61 constructor and the DEFAULT section. Additional substitutions may be
62 provided using the `vars' argument, which must be a dictionary whose
63 contents override any pre-existing defaults.
Guido van Rossum3d209861997-12-09 16:10:31 +000064
Barry Warsawf09f6a51999-01-26 22:01:37 +000065 getint(section, options)
66 like get(), but convert value to an integer
Guido van Rossum3d209861997-12-09 16:10:31 +000067
Barry Warsawf09f6a51999-01-26 22:01:37 +000068 getfloat(section, options)
69 like get(), but convert value to a float
Guido van Rossum3d209861997-12-09 16:10:31 +000070
Barry Warsawf09f6a51999-01-26 22:01:37 +000071 getboolean(section, options)
72 like get(), but convert value to a boolean (currently defined as 0 or
73 1, only)
Eric S. Raymond649685a2000-07-14 14:28:22 +000074
75 remove_section(section)
76 remove the given file section and all its options
77
78 remove_option(section, option)
79 remove the given option from the given section
80
81 set(section, option, value)
82 set the given option
83
84 write(fp)
85 write the configuration state in .ini format
Guido van Rossum3d209861997-12-09 16:10:31 +000086"""
87
88import sys
89import string
Barry Warsawbfa3f6b1998-07-01 20:41:12 +000090import re
Guido van Rossum3d209861997-12-09 16:10:31 +000091
92DEFAULTSECT = "DEFAULT"
93
Fred Drake2a37f9f2000-09-27 22:43:54 +000094MAX_INTERPOLATION_DEPTH = 10
95
Guido van Rossum3d209861997-12-09 16:10:31 +000096
97
98# exception classes
99class Error:
100 def __init__(self, msg=''):
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000101 self._msg = msg
Guido van Rossum3d209861997-12-09 16:10:31 +0000102 def __repr__(self):
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000103 return self._msg
Guido van Rossum3d209861997-12-09 16:10:31 +0000104
105class NoSectionError(Error):
106 def __init__(self, section):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000107 Error.__init__(self, 'No section: %s' % section)
108 self.section = section
Guido van Rossum3d209861997-12-09 16:10:31 +0000109
110class DuplicateSectionError(Error):
111 def __init__(self, section):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 Error.__init__(self, "Section %s already exists" % section)
113 self.section = section
Guido van Rossum3d209861997-12-09 16:10:31 +0000114
115class NoOptionError(Error):
116 def __init__(self, option, section):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000117 Error.__init__(self, "No option `%s' in section: %s" %
118 (option, section))
119 self.option = option
120 self.section = section
Guido van Rossum3d209861997-12-09 16:10:31 +0000121
122class InterpolationError(Error):
Barry Warsaw64462121998-08-06 18:48:41 +0000123 def __init__(self, reference, option, section, rawval):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000124 Error.__init__(self,
Barry Warsaw64462121998-08-06 18:48:41 +0000125 "Bad value substitution:\n"
126 "\tsection: [%s]\n"
127 "\toption : %s\n"
128 "\tkey : %s\n"
129 "\trawval : %s\n"
130 % (section, option, reference, rawval))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000131 self.reference = reference
132 self.option = option
133 self.section = section
Guido van Rossum3d209861997-12-09 16:10:31 +0000134
Fred Drake2a37f9f2000-09-27 22:43:54 +0000135class InterpolationDepthError(Error):
136 def __init__(self, option, section, rawval):
137 Error.__init__(self,
138 "Value interpolation too deeply recursive:\n"
139 "\tsection: [%s]\n"
140 "\toption : %s\n"
141 "\trawval : %s\n"
142 % (section, option, rawval))
143 self.option = option
144 self.section = section
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000145
146class ParsingError(Error):
147 def __init__(self, filename):
148 Error.__init__(self, 'File contains parsing errors: %s' % filename)
149 self.filename = filename
150 self.errors = []
151
152 def append(self, lineno, line):
153 self.errors.append((lineno, line))
154 self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
155
Fred Drake2a37f9f2000-09-27 22:43:54 +0000156class MissingSectionHeaderError(ParsingError):
157 def __init__(self, filename, lineno, line):
158 Error.__init__(
159 self,
160 'File contains no section headers.\nfile: %s, line: %d\n%s' %
161 (filename, lineno, line))
162 self.filename = filename
163 self.lineno = lineno
164 self.line = line
165
Guido van Rossum3d209861997-12-09 16:10:31 +0000166
167
168class ConfigParser:
169 def __init__(self, defaults=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000170 self.__sections = {}
171 if defaults is None:
172 self.__defaults = {}
173 else:
174 self.__defaults = defaults
Guido van Rossum3d209861997-12-09 16:10:31 +0000175
176 def defaults(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000177 return self.__defaults
Guido van Rossum3d209861997-12-09 16:10:31 +0000178
179 def sections(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000180 """Return a list of section names, excluding [DEFAULT]"""
181 # self.__sections will never have [DEFAULT] in it
182 return self.__sections.keys()
Guido van Rossum3d209861997-12-09 16:10:31 +0000183
184 def add_section(self, section):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000185 """Create a new section in the configuration.
Guido van Rossum3d209861997-12-09 16:10:31 +0000186
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000187 Raise DuplicateSectionError if a section by the specified name
188 already exists.
189 """
190 if self.__sections.has_key(section):
191 raise DuplicateSectionError(section)
192 self.__sections[section] = {}
Guido van Rossum3d209861997-12-09 16:10:31 +0000193
194 def has_section(self, section):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000195 """Indicate whether the named section is present in the configuration.
Guido van Rossum3d209861997-12-09 16:10:31 +0000196
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000197 The DEFAULT section is not acknowledged.
198 """
Fred Drake2a37f9f2000-09-27 22:43:54 +0000199 return section in self.sections()
Guido van Rossum3d209861997-12-09 16:10:31 +0000200
201 def options(self, section):
Guido van Rossuma5a24b71999-10-04 19:58:22 +0000202 """Return a list of option names for the given section name."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000203 try:
204 opts = self.__sections[section].copy()
205 except KeyError:
206 raise NoSectionError(section)
207 opts.update(self.__defaults)
Fred Drake2a37f9f2000-09-27 22:43:54 +0000208 if opts.has_key('__name__'):
209 del opts['__name__']
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000210 return opts.keys()
Guido van Rossum3d209861997-12-09 16:10:31 +0000211
Guido van Rossuma5a24b71999-10-04 19:58:22 +0000212 def has_option(self, section, option):
213 """Return whether the given section has the given option."""
Fred Drake2a37f9f2000-09-27 22:43:54 +0000214 return option in self.options(section)
Guido van Rossuma5a24b71999-10-04 19:58:22 +0000215
Guido van Rossum3d209861997-12-09 16:10:31 +0000216 def read(self, filenames):
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000217 """Read and parse a filename or a list of filenames.
218
219 Files that cannot be opened are silently ignored; this is
Barry Warsaw25394511999-10-12 16:12:48 +0000220 designed so that you can specify a list of potential
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000221 configuration file locations (e.g. current directory, user's
222 home directory, systemwide directory), and all existing
223 configuration files in the list will be read. A single
224 filename may also be given.
225 """
Fred Drakefd4114e2000-05-09 14:46:40 +0000226 if type(filenames) in [type(''), type(u'')]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000227 filenames = [filenames]
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000228 for filename in filenames:
229 try:
230 fp = open(filename)
231 except IOError:
232 continue
233 self.__read(fp, filename)
Fred Drake2438a481999-10-04 18:11:56 +0000234 fp.close()
Guido van Rossum3d209861997-12-09 16:10:31 +0000235
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000236 def readfp(self, fp, filename=None):
237 """Like read() but the argument must be a file-like object.
238
239 The `fp' argument must have a `readline' method. Optional
240 second argument is the `filename', which if not given, is
241 taken from fp.name. If fp has no `name' attribute, `<???>' is
242 used.
243
244 """
245 if filename is None:
246 try:
247 filename = fp.name
248 except AttributeError:
249 filename = '<???>'
250 self.__read(fp, filename)
251
Guido van Rossume6506e71999-01-26 19:29:25 +0000252 def get(self, section, option, raw=0, vars=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000253 """Get an option value for a given section.
Guido van Rossum3d209861997-12-09 16:10:31 +0000254
Barry Warsawf09f6a51999-01-26 22:01:37 +0000255 All % interpolations are expanded in the return values, based on the
256 defaults passed into the constructor, unless the optional argument
257 `raw' is true. Additional substitutions may be provided using the
258 `vars' argument, which must be a dictionary whose contents overrides
259 any pre-existing defaults.
Guido van Rossum3d209861997-12-09 16:10:31 +0000260
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000261 The section DEFAULT is special.
262 """
263 try:
264 sectdict = self.__sections[section].copy()
265 except KeyError:
266 if section == DEFAULTSECT:
267 sectdict = {}
268 else:
269 raise NoSectionError(section)
270 d = self.__defaults.copy()
271 d.update(sectdict)
Guido van Rossume6506e71999-01-26 19:29:25 +0000272 # Update with the entry specific variables
273 if vars:
274 d.update(vars)
Guido van Rossum9e480ad1999-06-17 18:41:42 +0000275 option = self.optionxform(option)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000276 try:
277 rawval = d[option]
278 except KeyError:
279 raise NoOptionError(option, section)
Fred Drake2a37f9f2000-09-27 22:43:54 +0000280
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000281 if raw:
282 return rawval
Guido van Rossum3d209861997-12-09 16:10:31 +0000283
Fred Drake2a37f9f2000-09-27 22:43:54 +0000284 # do the string interpolation
Guido van Rossume6506e71999-01-26 19:29:25 +0000285 value = rawval # Make it a pretty variable name
Guido van Rossum72ce8581999-02-12 14:13:10 +0000286 depth = 0
287 while depth < 10: # Loop through this until it's done
288 depth = depth + 1
Guido van Rossuma5a24b71999-10-04 19:58:22 +0000289 if string.find(value, "%(") >= 0:
Guido van Rossume6506e71999-01-26 19:29:25 +0000290 try:
291 value = value % d
292 except KeyError, key:
293 raise InterpolationError(key, option, section, rawval)
294 else:
Fred Drake2a37f9f2000-09-27 22:43:54 +0000295 break
296 if value.find("%(") >= 0:
297 raise InterpolationDepthError(option, section, rawval)
298 return value
Guido van Rossume6506e71999-01-26 19:29:25 +0000299
Guido van Rossum3d209861997-12-09 16:10:31 +0000300 def __get(self, section, conv, option):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000301 return conv(self.get(section, option))
Guido van Rossum3d209861997-12-09 16:10:31 +0000302
303 def getint(self, section, option):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000304 return self.__get(section, string.atoi, option)
Guido van Rossum3d209861997-12-09 16:10:31 +0000305
306 def getfloat(self, section, option):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000307 return self.__get(section, string.atof, option)
Guido van Rossum3d209861997-12-09 16:10:31 +0000308
309 def getboolean(self, section, option):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000310 v = self.get(section, option)
311 val = string.atoi(v)
312 if val not in (0, 1):
313 raise ValueError, 'Not a boolean: %s' % v
314 return val
Guido van Rossum3d209861997-12-09 16:10:31 +0000315
Guido van Rossum9e480ad1999-06-17 18:41:42 +0000316 def optionxform(self, optionstr):
317 return string.lower(optionstr)
318
Eric S. Raymond417c4892000-07-10 18:11:00 +0000319 def has_option(self, section, option):
320 """Check for the existence of a given option in a given section."""
321 if not section or section == "DEFAULT":
322 return self.__defaults.has_key(option)
323 elif not self.has_section(section):
324 return 0
325 else:
326 return self.__sections[section].has_key(option)
327
328 def set(self, section, option, value):
329 """Set an option."""
330 if not section or section == "DEFAULT":
331 sectdict = self.__defaults
332 else:
333 try:
334 sectdict = self.__sections[section]
335 except KeyError:
336 raise NoSectionError(section)
337 sectdict[option] = value
338
339 def write(self, fp):
340 """Write an .ini-format representation of the configuration state."""
341 if self.__defaults:
342 fp.write("[DEFAULT]\n")
Eric S. Raymond649685a2000-07-14 14:28:22 +0000343 for (key, value) in self.__defaults.items():
344 fp.write("%s = %s\n" % (key, value))
Eric S. Raymond417c4892000-07-10 18:11:00 +0000345 fp.write("\n")
346 for section in self.sections():
347 fp.write("[" + section + "]\n")
348 sectdict = self.__sections[section]
Eric S. Raymond649685a2000-07-14 14:28:22 +0000349 for (key, value) in sectdict.items():
Eric S. Raymond417c4892000-07-10 18:11:00 +0000350 if key == "__name__":
351 continue
Eric S. Raymond649685a2000-07-14 14:28:22 +0000352 fp.write("%s = %s\n" % (key, value))
Eric S. Raymond417c4892000-07-10 18:11:00 +0000353 fp.write("\n")
354
Thomas Woutersff4df6d2000-07-21 05:19:59 +0000355 def remove_option(self, section, option):
Eric S. Raymond649685a2000-07-14 14:28:22 +0000356 """Remove an option."""
357 if not section or section == "DEFAULT":
358 sectdict = self.__defaults
359 else:
360 try:
361 sectdict = self.__sections[section]
362 except KeyError:
363 raise NoSectionError(section)
364 existed = sectdict.has_key(key)
365 if existed:
366 del sectdict[key]
367 return existed
368
Thomas Woutersff4df6d2000-07-21 05:19:59 +0000369 def remove_section(self, section):
Eric S. Raymond649685a2000-07-14 14:28:22 +0000370 """Remove a file section."""
371 if self.__sections.has_key(section):
372 del self.__sections[section]
373 return 1
374 else:
375 return 0
376
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000377 #
378 # Regular expressions for parsing section headers and options. Note a
379 # slight semantic change from the previous version, because of the use
380 # of \w, _ is allowed in section header names.
Guido van Rossum9e480ad1999-06-17 18:41:42 +0000381 SECTCRE = re.compile(
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000382 r'\[' # [
Fred Drake2a37f9f2000-09-27 22:43:54 +0000383 r'(?P<header>[-\w_.*,(){} ]+)' # a lot of stuff found by IvL
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000384 r'\]' # ]
385 )
Guido van Rossum9e480ad1999-06-17 18:41:42 +0000386 OPTCRE = re.compile(
Fred Drake1ab41fc2000-02-28 23:23:55 +0000387 r'(?P<option>[-\w_.*,(){}]+)' # a lot of stuff found by IvL
Fred Drakec517b9b2000-02-28 20:59:03 +0000388 r'[ \t]*(?P<vi>[:=])[ \t]*' # any number of space/tab,
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000389 # followed by separator
390 # (either : or =), followed
391 # by any # space/tab
392 r'(?P<value>.*)$' # everything up to eol
393 )
394
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000395 def __read(self, fp, fpname):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000396 """Parse a sectioned setup file.
Guido van Rossum3d209861997-12-09 16:10:31 +0000397
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000398 The sections in setup file contains a title line at the top,
399 indicated by a name in square brackets (`[]'), plus key/value
400 options lines, indicated by `name: value' format lines.
401 Continuation are represented by an embedded newline then
402 leading whitespace. Blank lines, lines beginning with a '#',
403 and just about everything else is ignored.
404 """
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000405 cursect = None # None, or a dictionary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000406 optname = None
407 lineno = 0
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000408 e = None # None, or an exception
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000409 while 1:
410 line = fp.readline()
411 if not line:
412 break
413 lineno = lineno + 1
414 # comment or blank line?
415 if string.strip(line) == '' or line[0] in '#;':
416 continue
417 if string.lower(string.split(line)[0]) == 'rem' \
Fred Drakec517b9b2000-02-28 20:59:03 +0000418 and line[0] in "rR": # no leading whitespace
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 continue
420 # continuation line?
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000421 if line[0] in ' \t' and cursect is not None and optname:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000422 value = string.strip(line)
423 if value:
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000424 cursect[optname] = cursect[optname] + '\n ' + value
425 # a section header or option header?
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000426 else:
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000427 # is it a section header?
Guido van Rossum9e480ad1999-06-17 18:41:42 +0000428 mo = self.SECTCRE.match(line)
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000429 if mo:
430 sectname = mo.group('header')
431 if self.__sections.has_key(sectname):
432 cursect = self.__sections[sectname]
433 elif sectname == DEFAULTSECT:
434 cursect = self.__defaults
435 else:
Barry Warsaw64462121998-08-06 18:48:41 +0000436 cursect = {'__name__': sectname}
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000437 self.__sections[sectname] = cursect
438 # So sections can't start with a continuation line
439 optname = None
440 # no section header in the file?
441 elif cursect is None:
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000442 raise MissingSectionHeaderError(fpname, lineno, `line`)
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000443 # an option line?
444 else:
Guido van Rossum9e480ad1999-06-17 18:41:42 +0000445 mo = self.OPTCRE.match(line)
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000446 if mo:
Fred Drakec517b9b2000-02-28 20:59:03 +0000447 optname, vi, optval = mo.group('option', 'vi', 'value')
Jeremy Hylton820314e2000-03-03 20:43:57 +0000448 if vi in ('=', ':') and ';' in optval:
Fred Drakec517b9b2000-02-28 20:59:03 +0000449 # ';' is a comment delimiter only if it follows
450 # a spacing character
451 pos = string.find(optval, ';')
452 if pos and optval[pos-1] in string.whitespace:
453 optval = optval[:pos]
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000454 optval = string.strip(optval)
455 # allow empty values
456 if optval == '""':
457 optval = ''
Guido van Rossum41267362000-09-25 14:42:33 +0000458 cursect[self.optionxform(optname)] = optval
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000459 else:
460 # a non-fatal parsing error occurred. set up the
461 # exception but keep going. the exception will be
462 # raised at the end of the file and will contain a
463 # list of all bogus lines
464 if not e:
Guido van Rossum6a8d84b1999-10-04 18:57:27 +0000465 e = ParsingError(fpname)
Barry Warsawbfa3f6b1998-07-01 20:41:12 +0000466 e.append(lineno, `line`)
467 # if any parsing errors occurred, raise an exception
468 if e:
469 raise e