source: python/trunk/Lib/ConfigParser.py@ 394

Last change on this file since 394 was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

  • Property svn:eol-style set to native
File size: 27.1 KB
Line 
1"""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
5the style of RFC 822.
6
7The option values can contain format strings which refer to other values in
8the same section, or values in a special [DEFAULT] section.
9
10For 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 parsing a list of
23 configuration files, and managing the parsed database.
24
25 methods:
26
27 __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 its value is the section's name.
32
33 sections()
34 return all the configuration section names, sans DEFAULT
35
36 has_section(section)
37 return whether the given section exists
38
39 has_option(section, option)
40 return whether the given option exists in the given section
41
42 options(section)
43 return list of configuration options for the named section
44
45 read(filenames)
46 read and parse the list of named configuration files, given by
47 name. A single filename is also allowed. Non-existing files
48 are ignored. Return list of successfully read files.
49
50 readfp(fp, filename=None)
51 read and parse one configuration file, given as a file object.
52 The filename defaults to fp.name; it is only used in error
53 messages (if fp has no `name' attribute, the string `<???>' is used).
54
55 get(section, option, raw=False, vars=None)
56 return a string value for the named option. All % interpolations are
57 expanded in the return values, based on the defaults passed into the
58 constructor and the DEFAULT section. Additional substitutions may be
59 provided using the `vars' argument, which must be a dictionary whose
60 contents override any pre-existing defaults.
61
62 getint(section, options)
63 like get(), but convert value to an integer
64
65 getfloat(section, options)
66 like get(), but convert value to a float
67
68 getboolean(section, options)
69 like get(), but convert value to a boolean (currently case
70 insensitively defined as 0, false, no, off for False, and 1, true,
71 yes, on for True). Returns False or True.
72
73 items(section, raw=False, vars=None)
74 return a list of tuples with (name, value) for each option
75 in the section.
76
77 remove_section(section)
78 remove the given file section and all its options
79
80 remove_option(section, option)
81 remove the given option from the given section
82
83 set(section, option, value)
84 set the given option
85
86 write(fp)
87 write the configuration state in .ini format
88"""
89
90try:
91 from collections import OrderedDict as _default_dict
92except ImportError:
93 # fallback for setup.py which hasn't yet built _collections
94 _default_dict = dict
95
96import re
97
98__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError",
99 "InterpolationError", "InterpolationDepthError",
100 "InterpolationSyntaxError", "ParsingError",
101 "MissingSectionHeaderError",
102 "ConfigParser", "SafeConfigParser", "RawConfigParser",
103 "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
104
105DEFAULTSECT = "DEFAULT"
106
107MAX_INTERPOLATION_DEPTH = 10
108
109
110
111# exception classes
112class Error(Exception):
113 """Base class for ConfigParser exceptions."""
114
115 def _get_message(self):
116 """Getter for 'message'; needed only to override deprecation in
117 BaseException."""
118 return self.__message
119
120 def _set_message(self, value):
121 """Setter for 'message'; needed only to override deprecation in
122 BaseException."""
123 self.__message = value
124
125 # BaseException.message has been deprecated since Python 2.6. To prevent
126 # DeprecationWarning from popping up over this pre-existing attribute, use
127 # a new property that takes lookup precedence.
128 message = property(_get_message, _set_message)
129
130 def __init__(self, msg=''):
131 self.message = msg
132 Exception.__init__(self, msg)
133
134 def __repr__(self):
135 return self.message
136
137 __str__ = __repr__
138
139class NoSectionError(Error):
140 """Raised when no section matches a requested option."""
141
142 def __init__(self, section):
143 Error.__init__(self, 'No section: %r' % (section,))
144 self.section = section
145 self.args = (section, )
146
147class DuplicateSectionError(Error):
148 """Raised when a section is multiply-created."""
149
150 def __init__(self, section):
151 Error.__init__(self, "Section %r already exists" % section)
152 self.section = section
153 self.args = (section, )
154
155class NoOptionError(Error):
156 """A requested option was not found."""
157
158 def __init__(self, option, section):
159 Error.__init__(self, "No option %r in section: %r" %
160 (option, section))
161 self.option = option
162 self.section = section
163 self.args = (option, section)
164
165class InterpolationError(Error):
166 """Base class for interpolation-related exceptions."""
167
168 def __init__(self, option, section, msg):
169 Error.__init__(self, msg)
170 self.option = option
171 self.section = section
172 self.args = (option, section, msg)
173
174class InterpolationMissingOptionError(InterpolationError):
175 """A string substitution required a setting which was not available."""
176
177 def __init__(self, option, section, rawval, reference):
178 msg = ("Bad value substitution:\n"
179 "\tsection: [%s]\n"
180 "\toption : %s\n"
181 "\tkey : %s\n"
182 "\trawval : %s\n"
183 % (section, option, reference, rawval))
184 InterpolationError.__init__(self, option, section, msg)
185 self.reference = reference
186 self.args = (option, section, rawval, reference)
187
188class InterpolationSyntaxError(InterpolationError):
189 """Raised when the source text into which substitutions are made
190 does not conform to the required syntax."""
191
192class InterpolationDepthError(InterpolationError):
193 """Raised when substitutions are nested too deeply."""
194
195 def __init__(self, option, section, rawval):
196 msg = ("Value interpolation too deeply recursive:\n"
197 "\tsection: [%s]\n"
198 "\toption : %s\n"
199 "\trawval : %s\n"
200 % (section, option, rawval))
201 InterpolationError.__init__(self, option, section, msg)
202 self.args = (option, section, rawval)
203
204class ParsingError(Error):
205 """Raised when a configuration file does not follow legal syntax."""
206
207 def __init__(self, filename):
208 Error.__init__(self, 'File contains parsing errors: %s' % filename)
209 self.filename = filename
210 self.errors = []
211 self.args = (filename, )
212
213 def append(self, lineno, line):
214 self.errors.append((lineno, line))
215 self.message += '\n\t[line %2d]: %s' % (lineno, line)
216
217class MissingSectionHeaderError(ParsingError):
218 """Raised when a key-value pair is found before any section header."""
219
220 def __init__(self, filename, lineno, line):
221 Error.__init__(
222 self,
223 'File contains no section headers.\nfile: %s, line: %d\n%r' %
224 (filename, lineno, line))
225 self.filename = filename
226 self.lineno = lineno
227 self.line = line
228 self.args = (filename, lineno, line)
229
230
231class RawConfigParser:
232 def __init__(self, defaults=None, dict_type=_default_dict,
233 allow_no_value=False):
234 self._dict = dict_type
235 self._sections = self._dict()
236 self._defaults = self._dict()
237 if allow_no_value:
238 self._optcre = self.OPTCRE_NV
239 else:
240 self._optcre = self.OPTCRE
241 if defaults:
242 for key, value in defaults.items():
243 self._defaults[self.optionxform(key)] = value
244
245 def defaults(self):
246 return self._defaults
247
248 def sections(self):
249 """Return a list of section names, excluding [DEFAULT]"""
250 # self._sections will never have [DEFAULT] in it
251 return self._sections.keys()
252
253 def add_section(self, section):
254 """Create a new section in the configuration.
255
256 Raise DuplicateSectionError if a section by the specified name
257 already exists. Raise ValueError if name is DEFAULT or any of it's
258 case-insensitive variants.
259 """
260 if section.lower() == "default":
261 raise ValueError, 'Invalid section name: %s' % section
262
263 if section in self._sections:
264 raise DuplicateSectionError(section)
265 self._sections[section] = self._dict()
266
267 def has_section(self, section):
268 """Indicate whether the named section is present in the configuration.
269
270 The DEFAULT section is not acknowledged.
271 """
272 return section in self._sections
273
274 def options(self, section):
275 """Return a list of option names for the given section name."""
276 try:
277 opts = self._sections[section].copy()
278 except KeyError:
279 raise NoSectionError(section)
280 opts.update(self._defaults)
281 if '__name__' in opts:
282 del opts['__name__']
283 return opts.keys()
284
285 def read(self, filenames):
286 """Read and parse a filename or a list of filenames.
287
288 Files that cannot be opened are silently ignored; this is
289 designed so that you can specify a list of potential
290 configuration file locations (e.g. current directory, user's
291 home directory, systemwide directory), and all existing
292 configuration files in the list will be read. A single
293 filename may also be given.
294
295 Return list of successfully read files.
296 """
297 if isinstance(filenames, basestring):
298 filenames = [filenames]
299 read_ok = []
300 for filename in filenames:
301 try:
302 fp = open(filename)
303 except IOError:
304 continue
305 self._read(fp, filename)
306 fp.close()
307 read_ok.append(filename)
308 return read_ok
309
310 def readfp(self, fp, filename=None):
311 """Like read() but the argument must be a file-like object.
312
313 The `fp' argument must have a `readline' method. Optional
314 second argument is the `filename', which if not given, is
315 taken from fp.name. If fp has no `name' attribute, `<???>' is
316 used.
317
318 """
319 if filename is None:
320 try:
321 filename = fp.name
322 except AttributeError:
323 filename = '<???>'
324 self._read(fp, filename)
325
326 def get(self, section, option):
327 opt = self.optionxform(option)
328 if section not in self._sections:
329 if section != DEFAULTSECT:
330 raise NoSectionError(section)
331 if opt in self._defaults:
332 return self._defaults[opt]
333 else:
334 raise NoOptionError(option, section)
335 elif opt in self._sections[section]:
336 return self._sections[section][opt]
337 elif opt in self._defaults:
338 return self._defaults[opt]
339 else:
340 raise NoOptionError(option, section)
341
342 def items(self, section):
343 try:
344 d2 = self._sections[section]
345 except KeyError:
346 if section != DEFAULTSECT:
347 raise NoSectionError(section)
348 d2 = self._dict()
349 d = self._defaults.copy()
350 d.update(d2)
351 if "__name__" in d:
352 del d["__name__"]
353 return d.items()
354
355 def _get(self, section, conv, option):
356 return conv(self.get(section, option))
357
358 def getint(self, section, option):
359 return self._get(section, int, option)
360
361 def getfloat(self, section, option):
362 return self._get(section, float, option)
363
364 _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
365 '0': False, 'no': False, 'false': False, 'off': False}
366
367 def getboolean(self, section, option):
368 v = self.get(section, option)
369 if v.lower() not in self._boolean_states:
370 raise ValueError, 'Not a boolean: %s' % v
371 return self._boolean_states[v.lower()]
372
373 def optionxform(self, optionstr):
374 return optionstr.lower()
375
376 def has_option(self, section, option):
377 """Check for the existence of a given option in a given section."""
378 if not section or section == DEFAULTSECT:
379 option = self.optionxform(option)
380 return option in self._defaults
381 elif section not in self._sections:
382 return False
383 else:
384 option = self.optionxform(option)
385 return (option in self._sections[section]
386 or option in self._defaults)
387
388 def set(self, section, option, value=None):
389 """Set an option."""
390 if not section or section == DEFAULTSECT:
391 sectdict = self._defaults
392 else:
393 try:
394 sectdict = self._sections[section]
395 except KeyError:
396 raise NoSectionError(section)
397 sectdict[self.optionxform(option)] = value
398
399 def write(self, fp):
400 """Write an .ini-format representation of the configuration state."""
401 if self._defaults:
402 fp.write("[%s]\n" % DEFAULTSECT)
403 for (key, value) in self._defaults.items():
404 fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t')))
405 fp.write("\n")
406 for section in self._sections:
407 fp.write("[%s]\n" % section)
408 for (key, value) in self._sections[section].items():
409 if key == "__name__":
410 continue
411 if (value is not None) or (self._optcre == self.OPTCRE):
412 key = " = ".join((key, str(value).replace('\n', '\n\t')))
413 fp.write("%s\n" % (key))
414 fp.write("\n")
415
416 def remove_option(self, section, option):
417 """Remove an option."""
418 if not section or section == DEFAULTSECT:
419 sectdict = self._defaults
420 else:
421 try:
422 sectdict = self._sections[section]
423 except KeyError:
424 raise NoSectionError(section)
425 option = self.optionxform(option)
426 existed = option in sectdict
427 if existed:
428 del sectdict[option]
429 return existed
430
431 def remove_section(self, section):
432 """Remove a file section."""
433 existed = section in self._sections
434 if existed:
435 del self._sections[section]
436 return existed
437
438 #
439 # Regular expressions for parsing section headers and options.
440 #
441 SECTCRE = re.compile(
442 r'\[' # [
443 r'(?P<header>[^]]+)' # very permissive!
444 r'\]' # ]
445 )
446 OPTCRE = re.compile(
447 r'(?P<option>[^:=\s][^:=]*)' # very permissive!
448 r'\s*(?P<vi>[:=])\s*' # any number of space/tab,
449 # followed by separator
450 # (either : or =), followed
451 # by any # space/tab
452 r'(?P<value>.*)$' # everything up to eol
453 )
454 OPTCRE_NV = re.compile(
455 r'(?P<option>[^:=\s][^:=]*)' # very permissive!
456 r'\s*(?:' # any number of space/tab,
457 r'(?P<vi>[:=])\s*' # optionally followed by
458 # separator (either : or
459 # =), followed by any #
460 # space/tab
461 r'(?P<value>.*))?$' # everything up to eol
462 )
463
464 def _read(self, fp, fpname):
465 """Parse a sectioned setup file.
466
467 The sections in setup file contains a title line at the top,
468 indicated by a name in square brackets (`[]'), plus key/value
469 options lines, indicated by `name: value' format lines.
470 Continuations are represented by an embedded newline then
471 leading whitespace. Blank lines, lines beginning with a '#',
472 and just about everything else are ignored.
473 """
474 cursect = None # None, or a dictionary
475 optname = None
476 lineno = 0
477 e = None # None, or an exception
478 while True:
479 line = fp.readline()
480 if not line:
481 break
482 lineno = lineno + 1
483 # comment or blank line?
484 if line.strip() == '' or line[0] in '#;':
485 continue
486 if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
487 # no leading whitespace
488 continue
489 # continuation line?
490 if line[0].isspace() and cursect is not None and optname:
491 value = line.strip()
492 if value:
493 cursect[optname].append(value)
494 # a section header or option header?
495 else:
496 # is it a section header?
497 mo = self.SECTCRE.match(line)
498 if mo:
499 sectname = mo.group('header')
500 if sectname in self._sections:
501 cursect = self._sections[sectname]
502 elif sectname == DEFAULTSECT:
503 cursect = self._defaults
504 else:
505 cursect = self._dict()
506 cursect['__name__'] = sectname
507 self._sections[sectname] = cursect
508 # So sections can't start with a continuation line
509 optname = None
510 # no section header in the file?
511 elif cursect is None:
512 raise MissingSectionHeaderError(fpname, lineno, line)
513 # an option line?
514 else:
515 mo = self._optcre.match(line)
516 if mo:
517 optname, vi, optval = mo.group('option', 'vi', 'value')
518 optname = self.optionxform(optname.rstrip())
519 # This check is fine because the OPTCRE cannot
520 # match if it would set optval to None
521 if optval is not None:
522 if vi in ('=', ':') and ';' in optval:
523 # ';' is a comment delimiter only if it follows
524 # a spacing character
525 pos = optval.find(';')
526 if pos != -1 and optval[pos-1].isspace():
527 optval = optval[:pos]
528 optval = optval.strip()
529 # allow empty values
530 if optval == '""':
531 optval = ''
532 cursect[optname] = [optval]
533 else:
534 # valueless option handling
535 cursect[optname] = optval
536 else:
537 # a non-fatal parsing error occurred. set up the
538 # exception but keep going. the exception will be
539 # raised at the end of the file and will contain a
540 # list of all bogus lines
541 if not e:
542 e = ParsingError(fpname)
543 e.append(lineno, repr(line))
544 # if any parsing errors occurred, raise an exception
545 if e:
546 raise e
547
548 # join the multi-line values collected while reading
549 all_sections = [self._defaults]
550 all_sections.extend(self._sections.values())
551 for options in all_sections:
552 for name, val in options.items():
553 if isinstance(val, list):
554 options[name] = '\n'.join(val)
555
556import UserDict as _UserDict
557
558class _Chainmap(_UserDict.DictMixin):
559 """Combine multiple mappings for successive lookups.
560
561 For example, to emulate Python's normal lookup sequence:
562
563 import __builtin__
564 pylookup = _Chainmap(locals(), globals(), vars(__builtin__))
565 """
566
567 def __init__(self, *maps):
568 self._maps = maps
569
570 def __getitem__(self, key):
571 for mapping in self._maps:
572 try:
573 return mapping[key]
574 except KeyError:
575 pass
576 raise KeyError(key)
577
578 def keys(self):
579 result = []
580 seen = set()
581 for mapping in self._maps:
582 for key in mapping:
583 if key not in seen:
584 result.append(key)
585 seen.add(key)
586 return result
587
588class ConfigParser(RawConfigParser):
589
590 def get(self, section, option, raw=False, vars=None):
591 """Get an option value for a given section.
592
593 If `vars' is provided, it must be a dictionary. The option is looked up
594 in `vars' (if provided), `section', and in `defaults' in that order.
595
596 All % interpolations are expanded in the return values, unless the
597 optional argument `raw' is true. Values for interpolation keys are
598 looked up in the same manner as the option.
599
600 The section DEFAULT is special.
601 """
602 sectiondict = {}
603 try:
604 sectiondict = self._sections[section]
605 except KeyError:
606 if section != DEFAULTSECT:
607 raise NoSectionError(section)
608 # Update with the entry specific variables
609 vardict = {}
610 if vars:
611 for key, value in vars.items():
612 vardict[self.optionxform(key)] = value
613 d = _Chainmap(vardict, sectiondict, self._defaults)
614 option = self.optionxform(option)
615 try:
616 value = d[option]
617 except KeyError:
618 raise NoOptionError(option, section)
619
620 if raw or value is None:
621 return value
622 else:
623 return self._interpolate(section, option, value, d)
624
625 def items(self, section, raw=False, vars=None):
626 """Return a list of tuples with (name, value) for each option
627 in the section.
628
629 All % interpolations are expanded in the return values, based on the
630 defaults passed into the constructor, unless the optional argument
631 `raw' is true. Additional substitutions may be provided using the
632 `vars' argument, which must be a dictionary whose contents overrides
633 any pre-existing defaults.
634
635 The section DEFAULT is special.
636 """
637 d = self._defaults.copy()
638 try:
639 d.update(self._sections[section])
640 except KeyError:
641 if section != DEFAULTSECT:
642 raise NoSectionError(section)
643 # Update with the entry specific variables
644 if vars:
645 for key, value in vars.items():
646 d[self.optionxform(key)] = value
647 options = d.keys()
648 if "__name__" in options:
649 options.remove("__name__")
650 if raw:
651 return [(option, d[option])
652 for option in options]
653 else:
654 return [(option, self._interpolate(section, option, d[option], d))
655 for option in options]
656
657 def _interpolate(self, section, option, rawval, vars):
658 # do the string interpolation
659 value = rawval
660 depth = MAX_INTERPOLATION_DEPTH
661 while depth: # Loop through this until it's done
662 depth -= 1
663 if value and "%(" in value:
664 value = self._KEYCRE.sub(self._interpolation_replace, value)
665 try:
666 value = value % vars
667 except KeyError, e:
668 raise InterpolationMissingOptionError(
669 option, section, rawval, e.args[0])
670 else:
671 break
672 if value and "%(" in value:
673 raise InterpolationDepthError(option, section, rawval)
674 return value
675
676 _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
677
678 def _interpolation_replace(self, match):
679 s = match.group(1)
680 if s is None:
681 return match.group()
682 else:
683 return "%%(%s)s" % self.optionxform(s)
684
685
686class SafeConfigParser(ConfigParser):
687
688 def _interpolate(self, section, option, rawval, vars):
689 # do the string interpolation
690 L = []
691 self._interpolate_some(option, L, rawval, section, vars, 1)
692 return ''.join(L)
693
694 _interpvar_re = re.compile(r"%\(([^)]+)\)s")
695
696 def _interpolate_some(self, option, accum, rest, section, map, depth):
697 if depth > MAX_INTERPOLATION_DEPTH:
698 raise InterpolationDepthError(option, section, rest)
699 while rest:
700 p = rest.find("%")
701 if p < 0:
702 accum.append(rest)
703 return
704 if p > 0:
705 accum.append(rest[:p])
706 rest = rest[p:]
707 # p is no longer used
708 c = rest[1:2]
709 if c == "%":
710 accum.append("%")
711 rest = rest[2:]
712 elif c == "(":
713 m = self._interpvar_re.match(rest)
714 if m is None:
715 raise InterpolationSyntaxError(option, section,
716 "bad interpolation variable reference %r" % rest)
717 var = self.optionxform(m.group(1))
718 rest = rest[m.end():]
719 try:
720 v = map[var]
721 except KeyError:
722 raise InterpolationMissingOptionError(
723 option, section, rest, var)
724 if "%" in v:
725 self._interpolate_some(option, accum, v,
726 section, map, depth + 1)
727 else:
728 accum.append(v)
729 else:
730 raise InterpolationSyntaxError(
731 option, section,
732 "'%%' must be followed by '%%' or '(', found: %r" % (rest,))
733
734 def set(self, section, option, value=None):
735 """Set an option. Extend ConfigParser.set: check for string values."""
736 # The only legal non-string value if we allow valueless
737 # options is None, so we need to check if the value is a
738 # string if:
739 # - we do not allow valueless options, or
740 # - we allow valueless options but the value is not None
741 if self._optcre is self.OPTCRE or value:
742 if not isinstance(value, basestring):
743 raise TypeError("option values must be strings")
744 if value is not None:
745 # check for bad percent signs:
746 # first, replace all "good" interpolations
747 tmp_value = value.replace('%%', '')
748 tmp_value = self._interpvar_re.sub('', tmp_value)
749 # then, check if there's a lone percent sign left
750 if '%' in tmp_value:
751 raise ValueError("invalid interpolation syntax in %r at "
752 "position %d" % (value, tmp_value.find('%')))
753 ConfigParser.set(self, section, option, value)
Note: See TracBrowser for help on using the repository browser.