+++ /dev/null
-"""Configuration file parser.\r
-\r
-A setup file consists of sections, lead by a "[section]" header,\r
-and followed by "name: value" entries, with continuations and such in\r
-the style of RFC 822.\r
-\r
-The option values can contain format strings which refer to other values in\r
-the same section, or values in a special [DEFAULT] section.\r
-\r
-For example:\r
-\r
- something: %(dir)s/whatever\r
-\r
-would resolve the "%(dir)s" to the value of dir. All reference\r
-expansions are done late, on demand.\r
-\r
-Intrinsic defaults can be specified by passing them into the\r
-ConfigParser constructor as a dictionary.\r
-\r
-class:\r
-\r
-ConfigParser -- responsible for parsing a list of\r
- configuration files, and managing the parsed database.\r
-\r
- methods:\r
-\r
- __init__(defaults=None)\r
- create the parser and specify a dictionary of intrinsic defaults. The\r
- keys must be strings, the values must be appropriate for %()s string\r
- interpolation. Note that `__name__' is always an intrinsic default;\r
- its value is the section's name.\r
-\r
- sections()\r
- return all the configuration section names, sans DEFAULT\r
-\r
- has_section(section)\r
- return whether the given section exists\r
-\r
- has_option(section, option)\r
- return whether the given option exists in the given section\r
-\r
- options(section)\r
- return list of configuration options for the named section\r
-\r
- read(filenames)\r
- read and parse the list of named configuration files, given by\r
- name. A single filename is also allowed. Non-existing files\r
- are ignored. Return list of successfully read files.\r
-\r
- readfp(fp, filename=None)\r
- read and parse one configuration file, given as a file object.\r
- The filename defaults to fp.name; it is only used in error\r
- messages (if fp has no `name' attribute, the string `<???>' is used).\r
-\r
- get(section, option, raw=False, vars=None)\r
- return a string value for the named option. All % interpolations are\r
- expanded in the return values, based on the defaults passed into the\r
- constructor and the DEFAULT section. Additional substitutions may be\r
- provided using the `vars' argument, which must be a dictionary whose\r
- contents override any pre-existing defaults.\r
-\r
- getint(section, options)\r
- like get(), but convert value to an integer\r
-\r
- getfloat(section, options)\r
- like get(), but convert value to a float\r
-\r
- getboolean(section, options)\r
- like get(), but convert value to a boolean (currently case\r
- insensitively defined as 0, false, no, off for False, and 1, true,\r
- yes, on for True). Returns False or True.\r
-\r
- items(section, raw=False, vars=None)\r
- return a list of tuples with (name, value) for each option\r
- in the section.\r
-\r
- remove_section(section)\r
- remove the given file section and all its options\r
-\r
- remove_option(section, option)\r
- remove the given option from the given section\r
-\r
- set(section, option, value)\r
- set the given option\r
-\r
- write(fp)\r
- write the configuration state in .ini format\r
-"""\r
-\r
-try:\r
- from collections import OrderedDict as _default_dict\r
-except ImportError:\r
- # fallback for setup.py which hasn't yet built _collections\r
- _default_dict = dict\r
-\r
-import re\r
-\r
-__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError",\r
- "InterpolationError", "InterpolationDepthError",\r
- "InterpolationSyntaxError", "ParsingError",\r
- "MissingSectionHeaderError",\r
- "ConfigParser", "SafeConfigParser", "RawConfigParser",\r
- "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]\r
-\r
-DEFAULTSECT = "DEFAULT"\r
-\r
-MAX_INTERPOLATION_DEPTH = 10\r
-\r
-\r
-\r
-# exception classes\r
-class Error(Exception):\r
- """Base class for ConfigParser exceptions."""\r
-\r
- def _get_message(self):\r
- """Getter for 'message'; needed only to override deprecation in\r
- BaseException."""\r
- return self.__message\r
-\r
- def _set_message(self, value):\r
- """Setter for 'message'; needed only to override deprecation in\r
- BaseException."""\r
- self.__message = value\r
-\r
- # BaseException.message has been deprecated since Python 2.6. To prevent\r
- # DeprecationWarning from popping up over this pre-existing attribute, use\r
- # a new property that takes lookup precedence.\r
- message = property(_get_message, _set_message)\r
-\r
- def __init__(self, msg=''):\r
- self.message = msg\r
- Exception.__init__(self, msg)\r
-\r
- def __repr__(self):\r
- return self.message\r
-\r
- __str__ = __repr__\r
-\r
-class NoSectionError(Error):\r
- """Raised when no section matches a requested option."""\r
-\r
- def __init__(self, section):\r
- Error.__init__(self, 'No section: %r' % (section,))\r
- self.section = section\r
-\r
-class DuplicateSectionError(Error):\r
- """Raised when a section is multiply-created."""\r
-\r
- def __init__(self, section):\r
- Error.__init__(self, "Section %r already exists" % section)\r
- self.section = section\r
-\r
-class NoOptionError(Error):\r
- """A requested option was not found."""\r
-\r
- def __init__(self, option, section):\r
- Error.__init__(self, "No option %r in section: %r" %\r
- (option, section))\r
- self.option = option\r
- self.section = section\r
-\r
-class InterpolationError(Error):\r
- """Base class for interpolation-related exceptions."""\r
-\r
- def __init__(self, option, section, msg):\r
- Error.__init__(self, msg)\r
- self.option = option\r
- self.section = section\r
-\r
-class InterpolationMissingOptionError(InterpolationError):\r
- """A string substitution required a setting which was not available."""\r
-\r
- def __init__(self, option, section, rawval, reference):\r
- msg = ("Bad value substitution:\n"\r
- "\tsection: [%s]\n"\r
- "\toption : %s\n"\r
- "\tkey : %s\n"\r
- "\trawval : %s\n"\r
- % (section, option, reference, rawval))\r
- InterpolationError.__init__(self, option, section, msg)\r
- self.reference = reference\r
-\r
-class InterpolationSyntaxError(InterpolationError):\r
- """Raised when the source text into which substitutions are made\r
- does not conform to the required syntax."""\r
-\r
-class InterpolationDepthError(InterpolationError):\r
- """Raised when substitutions are nested too deeply."""\r
-\r
- def __init__(self, option, section, rawval):\r
- msg = ("Value interpolation too deeply recursive:\n"\r
- "\tsection: [%s]\n"\r
- "\toption : %s\n"\r
- "\trawval : %s\n"\r
- % (section, option, rawval))\r
- InterpolationError.__init__(self, option, section, msg)\r
-\r
-class ParsingError(Error):\r
- """Raised when a configuration file does not follow legal syntax."""\r
-\r
- def __init__(self, filename):\r
- Error.__init__(self, 'File contains parsing errors: %s' % filename)\r
- self.filename = filename\r
- self.errors = []\r
-\r
- def append(self, lineno, line):\r
- self.errors.append((lineno, line))\r
- self.message += '\n\t[line %2d]: %s' % (lineno, line)\r
-\r
-class MissingSectionHeaderError(ParsingError):\r
- """Raised when a key-value pair is found before any section header."""\r
-\r
- def __init__(self, filename, lineno, line):\r
- Error.__init__(\r
- self,\r
- 'File contains no section headers.\nfile: %s, line: %d\n%r' %\r
- (filename, lineno, line))\r
- self.filename = filename\r
- self.lineno = lineno\r
- self.line = line\r
-\r
-\r
-class RawConfigParser:\r
- def __init__(self, defaults=None, dict_type=_default_dict,\r
- allow_no_value=False):\r
- self._dict = dict_type\r
- self._sections = self._dict()\r
- self._defaults = self._dict()\r
- if allow_no_value:\r
- self._optcre = self.OPTCRE_NV\r
- else:\r
- self._optcre = self.OPTCRE\r
- if defaults:\r
- for key, value in defaults.items():\r
- self._defaults[self.optionxform(key)] = value\r
-\r
- def defaults(self):\r
- return self._defaults\r
-\r
- def sections(self):\r
- """Return a list of section names, excluding [DEFAULT]"""\r
- # self._sections will never have [DEFAULT] in it\r
- return self._sections.keys()\r
-\r
- def add_section(self, section):\r
- """Create a new section in the configuration.\r
-\r
- Raise DuplicateSectionError if a section by the specified name\r
- already exists. Raise ValueError if name is DEFAULT or any of it's\r
- case-insensitive variants.\r
- """\r
- if section.lower() == "default":\r
- raise ValueError, 'Invalid section name: %s' % section\r
-\r
- if section in self._sections:\r
- raise DuplicateSectionError(section)\r
- self._sections[section] = self._dict()\r
-\r
- def has_section(self, section):\r
- """Indicate whether the named section is present in the configuration.\r
-\r
- The DEFAULT section is not acknowledged.\r
- """\r
- return section in self._sections\r
-\r
- def options(self, section):\r
- """Return a list of option names for the given section name."""\r
- try:\r
- opts = self._sections[section].copy()\r
- except KeyError:\r
- raise NoSectionError(section)\r
- opts.update(self._defaults)\r
- if '__name__' in opts:\r
- del opts['__name__']\r
- return opts.keys()\r
-\r
- def read(self, filenames):\r
- """Read and parse a filename or a list of filenames.\r
-\r
- Files that cannot be opened are silently ignored; this is\r
- designed so that you can specify a list of potential\r
- configuration file locations (e.g. current directory, user's\r
- home directory, systemwide directory), and all existing\r
- configuration files in the list will be read. A single\r
- filename may also be given.\r
-\r
- Return list of successfully read files.\r
- """\r
- if isinstance(filenames, basestring):\r
- filenames = [filenames]\r
- read_ok = []\r
- for filename in filenames:\r
- try:\r
- fp = open(filename)\r
- except IOError:\r
- continue\r
- self._read(fp, filename)\r
- fp.close()\r
- read_ok.append(filename)\r
- return read_ok\r
-\r
- def readfp(self, fp, filename=None):\r
- """Like read() but the argument must be a file-like object.\r
-\r
- The `fp' argument must have a `readline' method. Optional\r
- second argument is the `filename', which if not given, is\r
- taken from fp.name. If fp has no `name' attribute, `<???>' is\r
- used.\r
-\r
- """\r
- if filename is None:\r
- try:\r
- filename = fp.name\r
- except AttributeError:\r
- filename = '<???>'\r
- self._read(fp, filename)\r
-\r
- def get(self, section, option):\r
- opt = self.optionxform(option)\r
- if section not in self._sections:\r
- if section != DEFAULTSECT:\r
- raise NoSectionError(section)\r
- if opt in self._defaults:\r
- return self._defaults[opt]\r
- else:\r
- raise NoOptionError(option, section)\r
- elif opt in self._sections[section]:\r
- return self._sections[section][opt]\r
- elif opt in self._defaults:\r
- return self._defaults[opt]\r
- else:\r
- raise NoOptionError(option, section)\r
-\r
- def items(self, section):\r
- try:\r
- d2 = self._sections[section]\r
- except KeyError:\r
- if section != DEFAULTSECT:\r
- raise NoSectionError(section)\r
- d2 = self._dict()\r
- d = self._defaults.copy()\r
- d.update(d2)\r
- if "__name__" in d:\r
- del d["__name__"]\r
- return d.items()\r
-\r
- def _get(self, section, conv, option):\r
- return conv(self.get(section, option))\r
-\r
- def getint(self, section, option):\r
- return self._get(section, int, option)\r
-\r
- def getfloat(self, section, option):\r
- return self._get(section, float, option)\r
-\r
- _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,\r
- '0': False, 'no': False, 'false': False, 'off': False}\r
-\r
- def getboolean(self, section, option):\r
- v = self.get(section, option)\r
- if v.lower() not in self._boolean_states:\r
- raise ValueError, 'Not a boolean: %s' % v\r
- return self._boolean_states[v.lower()]\r
-\r
- def optionxform(self, optionstr):\r
- return optionstr.lower()\r
-\r
- def has_option(self, section, option):\r
- """Check for the existence of a given option in a given section."""\r
- if not section or section == DEFAULTSECT:\r
- option = self.optionxform(option)\r
- return option in self._defaults\r
- elif section not in self._sections:\r
- return False\r
- else:\r
- option = self.optionxform(option)\r
- return (option in self._sections[section]\r
- or option in self._defaults)\r
-\r
- def set(self, section, option, value=None):\r
- """Set an option."""\r
- if not section or section == DEFAULTSECT:\r
- sectdict = self._defaults\r
- else:\r
- try:\r
- sectdict = self._sections[section]\r
- except KeyError:\r
- raise NoSectionError(section)\r
- sectdict[self.optionxform(option)] = value\r
-\r
- def write(self, fp):\r
- """Write an .ini-format representation of the configuration state."""\r
- if self._defaults:\r
- fp.write("[%s]\n" % DEFAULTSECT)\r
- for (key, value) in self._defaults.items():\r
- fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t')))\r
- fp.write("\n")\r
- for section in self._sections:\r
- fp.write("[%s]\n" % section)\r
- for (key, value) in self._sections[section].items():\r
- if key == "__name__":\r
- continue\r
- if (value is not None) or (self._optcre == self.OPTCRE):\r
- key = " = ".join((key, str(value).replace('\n', '\n\t')))\r
- fp.write("%s\n" % (key))\r
- fp.write("\n")\r
-\r
- def remove_option(self, section, option):\r
- """Remove an option."""\r
- if not section or section == DEFAULTSECT:\r
- sectdict = self._defaults\r
- else:\r
- try:\r
- sectdict = self._sections[section]\r
- except KeyError:\r
- raise NoSectionError(section)\r
- option = self.optionxform(option)\r
- existed = option in sectdict\r
- if existed:\r
- del sectdict[option]\r
- return existed\r
-\r
- def remove_section(self, section):\r
- """Remove a file section."""\r
- existed = section in self._sections\r
- if existed:\r
- del self._sections[section]\r
- return existed\r
-\r
- #\r
- # Regular expressions for parsing section headers and options.\r
- #\r
- SECTCRE = re.compile(\r
- r'\[' # [\r
- r'(?P<header>[^]]+)' # very permissive!\r
- r'\]' # ]\r
- )\r
- OPTCRE = re.compile(\r
- r'(?P<option>[^:=\s][^:=]*)' # very permissive!\r
- r'\s*(?P<vi>[:=])\s*' # any number of space/tab,\r
- # followed by separator\r
- # (either : or =), followed\r
- # by any # space/tab\r
- r'(?P<value>.*)$' # everything up to eol\r
- )\r
- OPTCRE_NV = re.compile(\r
- r'(?P<option>[^:=\s][^:=]*)' # very permissive!\r
- r'\s*(?:' # any number of space/tab,\r
- r'(?P<vi>[:=])\s*' # optionally followed by\r
- # separator (either : or\r
- # =), followed by any #\r
- # space/tab\r
- r'(?P<value>.*))?$' # everything up to eol\r
- )\r
-\r
- def _read(self, fp, fpname):\r
- """Parse a sectioned setup file.\r
-\r
- The sections in setup file contains a title line at the top,\r
- indicated by a name in square brackets (`[]'), plus key/value\r
- options lines, indicated by `name: value' format lines.\r
- Continuations are represented by an embedded newline then\r
- leading whitespace. Blank lines, lines beginning with a '#',\r
- and just about everything else are ignored.\r
- """\r
- cursect = None # None, or a dictionary\r
- optname = None\r
- lineno = 0\r
- e = None # None, or an exception\r
- while True:\r
- line = fp.readline()\r
- if not line:\r
- break\r
- lineno = lineno + 1\r
- # comment or blank line?\r
- if line.strip() == '' or line[0] in '#;':\r
- continue\r
- if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":\r
- # no leading whitespace\r
- continue\r
- # continuation line?\r
- if line[0].isspace() and cursect is not None and optname:\r
- value = line.strip()\r
- if value:\r
- cursect[optname].append(value)\r
- # a section header or option header?\r
- else:\r
- # is it a section header?\r
- mo = self.SECTCRE.match(line)\r
- if mo:\r
- sectname = mo.group('header')\r
- if sectname in self._sections:\r
- cursect = self._sections[sectname]\r
- elif sectname == DEFAULTSECT:\r
- cursect = self._defaults\r
- else:\r
- cursect = self._dict()\r
- cursect['__name__'] = sectname\r
- self._sections[sectname] = cursect\r
- # So sections can't start with a continuation line\r
- optname = None\r
- # no section header in the file?\r
- elif cursect is None:\r
- raise MissingSectionHeaderError(fpname, lineno, line)\r
- # an option line?\r
- else:\r
- mo = self._optcre.match(line)\r
- if mo:\r
- optname, vi, optval = mo.group('option', 'vi', 'value')\r
- optname = self.optionxform(optname.rstrip())\r
- # This check is fine because the OPTCRE cannot\r
- # match if it would set optval to None\r
- if optval is not None:\r
- if vi in ('=', ':') and ';' in optval:\r
- # ';' is a comment delimiter only if it follows\r
- # a spacing character\r
- pos = optval.find(';')\r
- if pos != -1 and optval[pos-1].isspace():\r
- optval = optval[:pos]\r
- optval = optval.strip()\r
- # allow empty values\r
- if optval == '""':\r
- optval = ''\r
- cursect[optname] = [optval]\r
- else:\r
- # valueless option handling\r
- cursect[optname] = optval\r
- else:\r
- # a non-fatal parsing error occurred. set up the\r
- # exception but keep going. the exception will be\r
- # raised at the end of the file and will contain a\r
- # list of all bogus lines\r
- if not e:\r
- e = ParsingError(fpname)\r
- e.append(lineno, repr(line))\r
- # if any parsing errors occurred, raise an exception\r
- if e:\r
- raise e\r
-\r
- # join the multi-line values collected while reading\r
- all_sections = [self._defaults]\r
- all_sections.extend(self._sections.values())\r
- for options in all_sections:\r
- for name, val in options.items():\r
- if isinstance(val, list):\r
- options[name] = '\n'.join(val)\r
-\r
-import UserDict as _UserDict\r
-\r
-class _Chainmap(_UserDict.DictMixin):\r
- """Combine multiple mappings for successive lookups.\r
-\r
- For example, to emulate Python's normal lookup sequence:\r
-\r
- import __builtin__\r
- pylookup = _Chainmap(locals(), globals(), vars(__builtin__))\r
- """\r
-\r
- def __init__(self, *maps):\r
- self._maps = maps\r
-\r
- def __getitem__(self, key):\r
- for mapping in self._maps:\r
- try:\r
- return mapping[key]\r
- except KeyError:\r
- pass\r
- raise KeyError(key)\r
-\r
- def keys(self):\r
- result = []\r
- seen = set()\r
- for mapping in self_maps:\r
- for key in mapping:\r
- if key not in seen:\r
- result.append(key)\r
- seen.add(key)\r
- return result\r
-\r
-class ConfigParser(RawConfigParser):\r
-\r
- def get(self, section, option, raw=False, vars=None):\r
- """Get an option value for a given section.\r
-\r
- If `vars' is provided, it must be a dictionary. The option is looked up\r
- in `vars' (if provided), `section', and in `defaults' in that order.\r
-\r
- All % interpolations are expanded in the return values, unless the\r
- optional argument `raw' is true. Values for interpolation keys are\r
- looked up in the same manner as the option.\r
-\r
- The section DEFAULT is special.\r
- """\r
- sectiondict = {}\r
- try:\r
- sectiondict = self._sections[section]\r
- except KeyError:\r
- if section != DEFAULTSECT:\r
- raise NoSectionError(section)\r
- # Update with the entry specific variables\r
- vardict = {}\r
- if vars:\r
- for key, value in vars.items():\r
- vardict[self.optionxform(key)] = value\r
- d = _Chainmap(vardict, sectiondict, self._defaults)\r
- option = self.optionxform(option)\r
- try:\r
- value = d[option]\r
- except KeyError:\r
- raise NoOptionError(option, section)\r
-\r
- if raw or value is None:\r
- return value\r
- else:\r
- return self._interpolate(section, option, value, d)\r
-\r
- def items(self, section, raw=False, vars=None):\r
- """Return a list of tuples with (name, value) for each option\r
- in the section.\r
-\r
- All % interpolations are expanded in the return values, based on the\r
- defaults passed into the constructor, unless the optional argument\r
- `raw' is true. Additional substitutions may be provided using the\r
- `vars' argument, which must be a dictionary whose contents overrides\r
- any pre-existing defaults.\r
-\r
- The section DEFAULT is special.\r
- """\r
- d = self._defaults.copy()\r
- try:\r
- d.update(self._sections[section])\r
- except KeyError:\r
- if section != DEFAULTSECT:\r
- raise NoSectionError(section)\r
- # Update with the entry specific variables\r
- if vars:\r
- for key, value in vars.items():\r
- d[self.optionxform(key)] = value\r
- options = d.keys()\r
- if "__name__" in options:\r
- options.remove("__name__")\r
- if raw:\r
- return [(option, d[option])\r
- for option in options]\r
- else:\r
- return [(option, self._interpolate(section, option, d[option], d))\r
- for option in options]\r
-\r
- def _interpolate(self, section, option, rawval, vars):\r
- # do the string interpolation\r
- value = rawval\r
- depth = MAX_INTERPOLATION_DEPTH\r
- while depth: # Loop through this until it's done\r
- depth -= 1\r
- if value and "%(" in value:\r
- value = self._KEYCRE.sub(self._interpolation_replace, value)\r
- try:\r
- value = value % vars\r
- except KeyError, e:\r
- raise InterpolationMissingOptionError(\r
- option, section, rawval, e.args[0])\r
- else:\r
- break\r
- if value and "%(" in value:\r
- raise InterpolationDepthError(option, section, rawval)\r
- return value\r
-\r
- _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")\r
-\r
- def _interpolation_replace(self, match):\r
- s = match.group(1)\r
- if s is None:\r
- return match.group()\r
- else:\r
- return "%%(%s)s" % self.optionxform(s)\r
-\r
-\r
-class SafeConfigParser(ConfigParser):\r
-\r
- def _interpolate(self, section, option, rawval, vars):\r
- # do the string interpolation\r
- L = []\r
- self._interpolate_some(option, L, rawval, section, vars, 1)\r
- return ''.join(L)\r
-\r
- _interpvar_re = re.compile(r"%\(([^)]+)\)s")\r
-\r
- def _interpolate_some(self, option, accum, rest, section, map, depth):\r
- if depth > MAX_INTERPOLATION_DEPTH:\r
- raise InterpolationDepthError(option, section, rest)\r
- while rest:\r
- p = rest.find("%")\r
- if p < 0:\r
- accum.append(rest)\r
- return\r
- if p > 0:\r
- accum.append(rest[:p])\r
- rest = rest[p:]\r
- # p is no longer used\r
- c = rest[1:2]\r
- if c == "%":\r
- accum.append("%")\r
- rest = rest[2:]\r
- elif c == "(":\r
- m = self._interpvar_re.match(rest)\r
- if m is None:\r
- raise InterpolationSyntaxError(option, section,\r
- "bad interpolation variable reference %r" % rest)\r
- var = self.optionxform(m.group(1))\r
- rest = rest[m.end():]\r
- try:\r
- v = map[var]\r
- except KeyError:\r
- raise InterpolationMissingOptionError(\r
- option, section, rest, var)\r
- if "%" in v:\r
- self._interpolate_some(option, accum, v,\r
- section, map, depth + 1)\r
- else:\r
- accum.append(v)\r
- else:\r
- raise InterpolationSyntaxError(\r
- option, section,\r
- "'%%' must be followed by '%%' or '(', found: %r" % (rest,))\r
-\r
- def set(self, section, option, value=None):\r
- """Set an option. Extend ConfigParser.set: check for string values."""\r
- # The only legal non-string value if we allow valueless\r
- # options is None, so we need to check if the value is a\r
- # string if:\r
- # - we do not allow valueless options, or\r
- # - we allow valueless options but the value is not None\r
- if self._optcre is self.OPTCRE or value:\r
- if not isinstance(value, basestring):\r
- raise TypeError("option values must be strings")\r
- if value is not None:\r
- # check for bad percent signs:\r
- # first, replace all "good" interpolations\r
- tmp_value = value.replace('%%', '')\r
- tmp_value = self._interpvar_re.sub('', tmp_value)\r
- # then, check if there's a lone percent sign left\r
- if '%' in tmp_value:\r
- raise ValueError("invalid interpolation syntax in %r at "\r
- "position %d" % (value, tmp_value.find('%')))\r
- ConfigParser.set(self, section, option, value)\r