[2] | 1 | """Configuration file parser.
|
---|
| 2 |
|
---|
| 3 | A setup file consists of sections, lead by a "[section]" header,
|
---|
| 4 | and followed by "name: value" entries, with continuations and such in
|
---|
| 5 | the style of RFC 822.
|
---|
| 6 |
|
---|
| 7 | The option values can contain format strings which refer to other values in
|
---|
| 8 | the same section, or values in a special [DEFAULT] section.
|
---|
| 9 |
|
---|
| 10 | For example:
|
---|
| 11 |
|
---|
| 12 | something: %(dir)s/whatever
|
---|
| 13 |
|
---|
| 14 | would resolve the "%(dir)s" to the value of dir. All reference
|
---|
| 15 | expansions are done late, on demand.
|
---|
| 16 |
|
---|
| 17 | Intrinsic defaults can be specified by passing them into the
|
---|
| 18 | ConfigParser constructor as a dictionary.
|
---|
| 19 |
|
---|
| 20 | class:
|
---|
| 21 |
|
---|
| 22 | ConfigParser -- 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 |
|
---|
[391] | 90 | try:
|
---|
| 91 | from collections import OrderedDict as _default_dict
|
---|
| 92 | except ImportError:
|
---|
| 93 | # fallback for setup.py which hasn't yet built _collections
|
---|
| 94 | _default_dict = dict
|
---|
| 95 |
|
---|
[2] | 96 | import 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 |
|
---|
| 105 | DEFAULTSECT = "DEFAULT"
|
---|
| 106 |
|
---|
| 107 | MAX_INTERPOLATION_DEPTH = 10
|
---|
| 108 |
|
---|
| 109 |
|
---|
| 110 |
|
---|
| 111 | # exception classes
|
---|
| 112 | class 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 |
|
---|
| 139 | class 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
|
---|
[391] | 145 | self.args = (section, )
|
---|
[2] | 146 |
|
---|
| 147 | class 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
|
---|
[391] | 153 | self.args = (section, )
|
---|
[2] | 154 |
|
---|
| 155 | class 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
|
---|
[391] | 163 | self.args = (option, section)
|
---|
[2] | 164 |
|
---|
| 165 | class 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
|
---|
[391] | 172 | self.args = (option, section, msg)
|
---|
[2] | 173 |
|
---|
| 174 | class 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
|
---|
[391] | 186 | self.args = (option, section, rawval, reference)
|
---|
[2] | 187 |
|
---|
| 188 | class InterpolationSyntaxError(InterpolationError):
|
---|
| 189 | """Raised when the source text into which substitutions are made
|
---|
| 190 | does not conform to the required syntax."""
|
---|
| 191 |
|
---|
| 192 | class 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)
|
---|
[391] | 202 | self.args = (option, section, rawval)
|
---|
[2] | 203 |
|
---|
| 204 | class 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 = []
|
---|
[391] | 211 | self.args = (filename, )
|
---|
[2] | 212 |
|
---|
| 213 | def append(self, lineno, line):
|
---|
| 214 | self.errors.append((lineno, line))
|
---|
| 215 | self.message += '\n\t[line %2d]: %s' % (lineno, line)
|
---|
| 216 |
|
---|
| 217 | class 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
|
---|
[391] | 228 | self.args = (filename, lineno, line)
|
---|
[2] | 229 |
|
---|
| 230 |
|
---|
| 231 | class RawConfigParser:
|
---|
[391] | 232 | def __init__(self, defaults=None, dict_type=_default_dict,
|
---|
| 233 | allow_no_value=False):
|
---|
[2] | 234 | self._dict = dict_type
|
---|
| 235 | self._sections = self._dict()
|
---|
| 236 | self._defaults = self._dict()
|
---|
[391] | 237 | if allow_no_value:
|
---|
| 238 | self._optcre = self.OPTCRE_NV
|
---|
| 239 | else:
|
---|
| 240 | self._optcre = self.OPTCRE
|
---|
[2] | 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 |
|
---|
[391] | 388 | def set(self, section, option, value=None):
|
---|
[2] | 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():
|
---|
[391] | 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))
|
---|
[2] | 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 | )
|
---|
[391] | 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 | )
|
---|
[2] | 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 | """
|
---|
[391] | 474 | cursect = None # None, or a dictionary
|
---|
[2] | 475 | optname = None
|
---|
| 476 | lineno = 0
|
---|
[391] | 477 | e = None # None, or an exception
|
---|
[2] | 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:
|
---|
[391] | 493 | cursect[optname].append(value)
|
---|
[2] | 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:
|
---|
[391] | 515 | mo = self._optcre.match(line)
|
---|
[2] | 516 | if mo:
|
---|
| 517 | optname, vi, optval = mo.group('option', 'vi', 'value')
|
---|
| 518 | optname = self.optionxform(optname.rstrip())
|
---|
[391] | 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
|
---|
[2] | 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 |
|
---|
[391] | 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)
|
---|
[2] | 555 |
|
---|
[391] | 556 | import UserDict as _UserDict
|
---|
| 557 |
|
---|
| 558 | class _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 |
|
---|
[2] | 588 | class ConfigParser(RawConfigParser):
|
---|
| 589 |
|
---|
| 590 | def get(self, section, option, raw=False, vars=None):
|
---|
| 591 | """Get an option value for a given section.
|
---|
| 592 |
|
---|
[391] | 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.
|
---|
[2] | 595 |
|
---|
[391] | 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 |
|
---|
[2] | 600 | The section DEFAULT is special.
|
---|
| 601 | """
|
---|
[391] | 602 | sectiondict = {}
|
---|
[2] | 603 | try:
|
---|
[391] | 604 | sectiondict = self._sections[section]
|
---|
[2] | 605 | except KeyError:
|
---|
| 606 | if section != DEFAULTSECT:
|
---|
| 607 | raise NoSectionError(section)
|
---|
| 608 | # Update with the entry specific variables
|
---|
[391] | 609 | vardict = {}
|
---|
[2] | 610 | if vars:
|
---|
| 611 | for key, value in vars.items():
|
---|
[391] | 612 | vardict[self.optionxform(key)] = value
|
---|
| 613 | d = _Chainmap(vardict, sectiondict, self._defaults)
|
---|
[2] | 614 | option = self.optionxform(option)
|
---|
| 615 | try:
|
---|
| 616 | value = d[option]
|
---|
| 617 | except KeyError:
|
---|
| 618 | raise NoOptionError(option, section)
|
---|
| 619 |
|
---|
[391] | 620 | if raw or value is None:
|
---|
[2] | 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
|
---|
[391] | 663 | if value and "%(" in value:
|
---|
[2] | 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
|
---|
[391] | 672 | if value and "%(" in value:
|
---|
[2] | 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 |
|
---|
| 686 | class 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 |
|
---|
[391] | 734 | def set(self, section, option, value=None):
|
---|
[2] | 735 | """Set an option. Extend ConfigParser.set: check for string values."""
|
---|
[391] | 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('%')))
|
---|
[2] | 753 | ConfigParser.set(self, section, option, value)
|
---|