0001 """Configuration file parser. 0002 0003 A setup file consists of sections, lead by a "[section]" header, 0004 and followed by "name: value" entries, with continuations and such in 0005 the style of RFC 822. 0006 0007 The option values can contain format strings which refer to other values in 0008 the same section, or values in a special [DEFAULT] section. 0009 0010 For example: 0011 0012 something: %(dir)s/whatever 0013 0014 would resolve the "%(dir)s" to the value of dir. All reference 0015 expansions are done late, on demand. 0016 0017 Intrinsic defaults can be specified by passing them into the 0018 ConfigParser constructor as a dictionary. 0019 0020 class: 0021 0022 ConfigParser -- responsible for parsing a list of 0023 configuration files, and managing the parsed database. 0024 0025 methods: 0026 0027 __init__(defaults=None) 0028 create the parser and specify a dictionary of intrinsic defaults. The 0029 keys must be strings, the values must be appropriate for %()s string 0030 interpolation. Note that `__name__' is always an intrinsic default; 0031 it's value is the section's name. 0032 0033 sections() 0034 return all the configuration section names, sans DEFAULT 0035 0036 has_section(section) 0037 return whether the given section exists 0038 0039 has_option(section, option) 0040 return whether the given option exists in the given section 0041 0042 options(section) 0043 return list of configuration options for the named section 0044 0045 read(filenames) 0046 read and parse the list of named configuration files, given by 0047 name. A single filename is also allowed. Non-existing files 0048 are ignored. Return list of successfully read files. 0049 0050 readfp(fp, filename=None) 0051 read and parse one configuration file, given as a file object. 0052 The filename defaults to fp.name; it is only used in error 0053 messages (if fp has no `name' attribute, the string `<???>' is used). 0054 0055 get(section, option, raw=False, vars=None) 0056 return a string value for the named option. All % interpolations are 0057 expanded in the return values, based on the defaults passed into the 0058 constructor and the DEFAULT section. Additional substitutions may be 0059 provided using the `vars' argument, which must be a dictionary whose 0060 contents override any pre-existing defaults. 0061 0062 getint(section, options) 0063 like get(), but convert value to an integer 0064 0065 getfloat(section, options) 0066 like get(), but convert value to a float 0067 0068 getboolean(section, options) 0069 like get(), but convert value to a boolean (currently case 0070 insensitively defined as 0, false, no, off for False, and 1, true, 0071 yes, on for True). Returns False or True. 0072 0073 items(section, raw=False, vars=None) 0074 return a list of tuples with (name, value) for each option 0075 in the section. 0076 0077 remove_section(section) 0078 remove the given file section and all its options 0079 0080 remove_option(section, option) 0081 remove the given option from the given section 0082 0083 set(section, option, value) 0084 set the given option 0085 0086 write(fp) 0087 write the configuration state in .ini format 0088 """ 0089 0090 import re 0091 0092 __all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError", 0093 "InterpolationError", "InterpolationDepthError", 0094 "InterpolationSyntaxError", "ParsingError", 0095 "MissingSectionHeaderError", 0096 "ConfigParser", "SafeConfigParser", "RawConfigParser", 0097 "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"] 0098 0099 DEFAULTSECT = "DEFAULT" 0100 0101 MAX_INTERPOLATION_DEPTH = 10 0102 0103 0104 0105 # exception classes 0106 class Error(Exception): 0107 """Base class for ConfigParser exceptions.""" 0108 0109 def __init__(self, msg=''): 0110 self.message = msg 0111 Exception.__init__(self, msg) 0112 0113 def __repr__(self): 0114 return self.message 0115 0116 __str__ = __repr__ 0117 0118 class NoSectionError(Error): 0119 """Raised when no section matches a requested option.""" 0120 0121 def __init__(self, section): 0122 Error.__init__(self, 'No section: %r' % (section,)) 0123 self.section = section 0124 0125 class DuplicateSectionError(Error): 0126 """Raised when a section is multiply-created.""" 0127 0128 def __init__(self, section): 0129 Error.__init__(self, "Section %r already exists" % section) 0130 self.section = section 0131 0132 class NoOptionError(Error): 0133 """A requested option was not found.""" 0134 0135 def __init__(self, option, section): 0136 Error.__init__(self, "No option %r in section: %r" % 0137 (option, section)) 0138 self.option = option 0139 self.section = section 0140 0141 class InterpolationError(Error): 0142 """Base class for interpolation-related exceptions.""" 0143 0144 def __init__(self, option, section, msg): 0145 Error.__init__(self, msg) 0146 self.option = option 0147 self.section = section 0148 0149 class InterpolationMissingOptionError(InterpolationError): 0150 """A string substitution required a setting which was not available.""" 0151 0152 def __init__(self, option, section, rawval, reference): 0153 msg = ("Bad value substitution:\n" 0154 "\tsection: [%s]\n" 0155 "\toption : %s\n" 0156 "\tkey : %s\n" 0157 "\trawval : %s\n" 0158 % (section, option, reference, rawval)) 0159 InterpolationError.__init__(self, option, section, msg) 0160 self.reference = reference 0161 0162 class InterpolationSyntaxError(InterpolationError): 0163 """Raised when the source text into which substitutions are made 0164 does not conform to the required syntax.""" 0165 0166 class InterpolationDepthError(InterpolationError): 0167 """Raised when substitutions are nested too deeply.""" 0168 0169 def __init__(self, option, section, rawval): 0170 msg = ("Value interpolation too deeply recursive:\n" 0171 "\tsection: [%s]\n" 0172 "\toption : %s\n" 0173 "\trawval : %s\n" 0174 % (section, option, rawval)) 0175 InterpolationError.__init__(self, option, section, msg) 0176 0177 class ParsingError(Error): 0178 """Raised when a configuration file does not follow legal syntax.""" 0179 0180 def __init__(self, filename): 0181 Error.__init__(self, 'File contains parsing errors: %s' % filename) 0182 self.filename = filename 0183 self.errors = [] 0184 0185 def append(self, lineno, line): 0186 self.errors.append((lineno, line)) 0187 self.message += '\n\t[line %2d]: %s' % (lineno, line) 0188 0189 class MissingSectionHeaderError(ParsingError): 0190 """Raised when a key-value pair is found before any section header.""" 0191 0192 def __init__(self, filename, lineno, line): 0193 Error.__init__( 0194 self, 0195 'File contains no section headers.\nfile: %s, line: %d\n%r' % 0196 (filename, lineno, line)) 0197 self.filename = filename 0198 self.lineno = lineno 0199 self.line = line 0200 0201 0202 0203 class RawConfigParser: 0204 def __init__(self, defaults=None): 0205 self._sections = {} 0206 self._defaults = {} 0207 if defaults: 0208 for key, value in defaults.items(): 0209 self._defaults[self.optionxform(key)] = value 0210 0211 def defaults(self): 0212 return self._defaults 0213 0214 def sections(self): 0215 """Return a list of section names, excluding [DEFAULT]""" 0216 # self._sections will never have [DEFAULT] in it 0217 return self._sections.keys() 0218 0219 def add_section(self, section): 0220 """Create a new section in the configuration. 0221 0222 Raise DuplicateSectionError if a section by the specified name 0223 already exists. 0224 """ 0225 if section in self._sections: 0226 raise DuplicateSectionError(section) 0227 self._sections[section] = {} 0228 0229 def has_section(self, section): 0230 """Indicate whether the named section is present in the configuration. 0231 0232 The DEFAULT section is not acknowledged. 0233 """ 0234 return section in self._sections 0235 0236 def options(self, section): 0237 """Return a list of option names for the given section name.""" 0238 try: 0239 opts = self._sections[section].copy() 0240 except KeyError: 0241 raise NoSectionError(section) 0242 opts.update(self._defaults) 0243 if '__name__' in opts: 0244 del opts['__name__'] 0245 return opts.keys() 0246 0247 def read(self, filenames): 0248 """Read and parse a filename or a list of filenames. 0249 0250 Files that cannot be opened are silently ignored; this is 0251 designed so that you can specify a list of potential 0252 configuration file locations (e.g. current directory, user's 0253 home directory, systemwide directory), and all existing 0254 configuration files in the list will be read. A single 0255 filename may also be given. 0256 0257 Return list of successfully read files. 0258 """ 0259 if isinstance(filenames, basestring): 0260 filenames = [filenames] 0261 read_ok = [] 0262 for filename in filenames: 0263 try: 0264 fp = open(filename) 0265 except IOError: 0266 continue 0267 self._read(fp, filename) 0268 fp.close() 0269 read_ok.append(filename) 0270 return read_ok 0271 0272 def readfp(self, fp, filename=None): 0273 """Like read() but the argument must be a file-like object. 0274 0275 The `fp' argument must have a `readline' method. Optional 0276 second argument is the `filename', which if not given, is 0277 taken from fp.name. If fp has no `name' attribute, `<???>' is 0278 used. 0279 0280 """ 0281 if filename is None: 0282 try: 0283 filename = fp.name 0284 except AttributeError: 0285 filename = '<???>' 0286 self._read(fp, filename) 0287 0288 def get(self, section, option): 0289 opt = self.optionxform(option) 0290 if section not in self._sections: 0291 if section != DEFAULTSECT: 0292 raise NoSectionError(section) 0293 if opt in self._defaults: 0294 return self._defaults[opt] 0295 else: 0296 raise NoOptionError(option, section) 0297 elif opt in self._sections[section]: 0298 return self._sections[section][opt] 0299 elif opt in self._defaults: 0300 return self._defaults[opt] 0301 else: 0302 raise NoOptionError(option, section) 0303 0304 def items(self, section): 0305 try: 0306 d2 = self._sections[section] 0307 except KeyError: 0308 if section != DEFAULTSECT: 0309 raise NoSectionError(section) 0310 d2 = {} 0311 d = self._defaults.copy() 0312 d.update(d2) 0313 if "__name__" in d: 0314 del d["__name__"] 0315 return d.items() 0316 0317 def _get(self, section, conv, option): 0318 return conv(self.get(section, option)) 0319 0320 def getint(self, section, option): 0321 return self._get(section, int, option) 0322 0323 def getfloat(self, section, option): 0324 return self._get(section, float, option) 0325 0326 _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True, 0327 '0': False, 'no': False, 'false': False, 'off': False} 0328 0329 def getboolean(self, section, option): 0330 v = self.get(section, option) 0331 if v.lower() not in self._boolean_states: 0332 raise ValueError, 'Not a boolean: %s' % v 0333 return self._boolean_states[v.lower()] 0334 0335 def optionxform(self, optionstr): 0336 return optionstr.lower() 0337 0338 def has_option(self, section, option): 0339 """Check for the existence of a given option in a given section.""" 0340 if not section or section == DEFAULTSECT: 0341 option = self.optionxform(option) 0342 return option in self._defaults 0343 elif section not in self._sections: 0344 return False 0345 else: 0346 option = self.optionxform(option) 0347 return (option in self._sections[section] 0348 or option in self._defaults) 0349 0350 def set(self, section, option, value): 0351 """Set an option.""" 0352 if not section or section == DEFAULTSECT: 0353 sectdict = self._defaults 0354 else: 0355 try: 0356 sectdict = self._sections[section] 0357 except KeyError: 0358 raise NoSectionError(section) 0359 sectdict[self.optionxform(option)] = value 0360 0361 def write(self, fp): 0362 """Write an .ini-format representation of the configuration state.""" 0363 if self._defaults: 0364 fp.write("[%s]\n" % DEFAULTSECT) 0365 for (key, value) in self._defaults.items(): 0366 fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) 0367 fp.write("\n") 0368 for section in self._sections: 0369 fp.write("[%s]\n" % section) 0370 for (key, value) in self._sections[section].items(): 0371 if key != "__name__": 0372 fp.write("%s = %s\n" % 0373 (key, str(value).replace('\n', '\n\t'))) 0374 fp.write("\n") 0375 0376 def remove_option(self, section, option): 0377 """Remove an option.""" 0378 if not section or section == DEFAULTSECT: 0379 sectdict = self._defaults 0380 else: 0381 try: 0382 sectdict = self._sections[section] 0383 except KeyError: 0384 raise NoSectionError(section) 0385 option = self.optionxform(option) 0386 existed = option in sectdict 0387 if existed: 0388 del sectdict[option] 0389 return existed 0390 0391 def remove_section(self, section): 0392 """Remove a file section.""" 0393 existed = section in self._sections 0394 if existed: 0395 del self._sections[section] 0396 return existed 0397 0398 # 0399 # Regular expressions for parsing section headers and options. 0400 # 0401 SECTCRE = re.compile( 0402 r'\[' # [ 0403 r'(?P<header>[^]]+)' # very permissive! 0404 r'\]' # ] 0405 ) 0406 OPTCRE = re.compile( 0407 r'(?P<option>[^:=\s][^:=]*)' # very permissive! 0408 r'\s*(?P<vi>[:=])\s*' # any number of space/tab, 0409 # followed by separator 0410 # (either : or =), followed 0411 # by any # space/tab 0412 r'(?P<value>.*)$' # everything up to eol 0413 ) 0414 0415 def _read(self, fp, fpname): 0416 """Parse a sectioned setup file. 0417 0418 The sections in setup file contains a title line at the top, 0419 indicated by a name in square brackets (`[]'), plus key/value 0420 options lines, indicated by `name: value' format lines. 0421 Continuations are represented by an embedded newline then 0422 leading whitespace. Blank lines, lines beginning with a '#', 0423 and just about everything else are ignored. 0424 """ 0425 cursect = None # None, or a dictionary 0426 optname = None 0427 lineno = 0 0428 e = None # None, or an exception 0429 while True: 0430 line = fp.readline() 0431 if not line: 0432 break 0433 lineno = lineno + 1 0434 # comment or blank line? 0435 if line.strip() == '' or line[0] in '#;': 0436 continue 0437 if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": 0438 # no leading whitespace 0439 continue 0440 # continuation line? 0441 if line[0].isspace() and cursect is not None and optname: 0442 value = line.strip() 0443 if value: 0444 cursect[optname] = "%s\n%s" % (cursect[optname], value) 0445 # a section header or option header? 0446 else: 0447 # is it a section header? 0448 mo = self.SECTCRE.match(line) 0449 if mo: 0450 sectname = mo.group('header') 0451 if sectname in self._sections: 0452 cursect = self._sections[sectname] 0453 elif sectname == DEFAULTSECT: 0454 cursect = self._defaults 0455 else: 0456 cursect = {'__name__': sectname} 0457 self._sections[sectname] = cursect 0458 # So sections can't start with a continuation line 0459 optname = None 0460 # no section header in the file? 0461 elif cursect is None: 0462 raise MissingSectionHeaderError(fpname, lineno, line) 0463 # an option line? 0464 else: 0465 mo = self.OPTCRE.match(line) 0466 if mo: 0467 optname, vi, optval = mo.group('option', 'vi', 'value') 0468 if vi in ('=', ':') and ';' in optval: 0469 # ';' is a comment delimiter only if it follows 0470 # a spacing character 0471 pos = optval.find(';') 0472 if pos != -1 and optval[pos-1].isspace(): 0473 optval = optval[:pos] 0474 optval = optval.strip() 0475 # allow empty values 0476 if optval == '""': 0477 optval = '' 0478 optname = self.optionxform(optname.rstrip()) 0479 cursect[optname] = optval 0480 else: 0481 # a non-fatal parsing error occurred. set up the 0482 # exception but keep going. the exception will be 0483 # raised at the end of the file and will contain a 0484 # list of all bogus lines 0485 if not e: 0486 e = ParsingError(fpname) 0487 e.append(lineno, repr(line)) 0488 # if any parsing errors occurred, raise an exception 0489 if e: 0490 raise e 0491 0492 0493 class ConfigParser(RawConfigParser): 0494 0495 def get(self, section, option, raw=False, vars=None): 0496 """Get an option value for a given section. 0497 0498 All % interpolations are expanded in the return values, based on the 0499 defaults passed into the constructor, unless the optional argument 0500 `raw' is true. Additional substitutions may be provided using the 0501 `vars' argument, which must be a dictionary whose contents overrides 0502 any pre-existing defaults. 0503 0504 The section DEFAULT is special. 0505 """ 0506 d = self._defaults.copy() 0507 try: 0508 d.update(self._sections[section]) 0509 except KeyError: 0510 if section != DEFAULTSECT: 0511 raise NoSectionError(section) 0512 # Update with the entry specific variables 0513 if vars: 0514 for key, value in vars.items(): 0515 d[self.optionxform(key)] = value 0516 option = self.optionxform(option) 0517 try: 0518 value = d[option] 0519 except KeyError: 0520 raise NoOptionError(option, section) 0521 0522 if raw: 0523 return value 0524 else: 0525 return self._interpolate(section, option, value, d) 0526 0527 def items(self, section, raw=False, vars=None): 0528 """Return a list of tuples with (name, value) for each option 0529 in the section. 0530 0531 All % interpolations are expanded in the return values, based on the 0532 defaults passed into the constructor, unless the optional argument 0533 `raw' is true. Additional substitutions may be provided using the 0534 `vars' argument, which must be a dictionary whose contents overrides 0535 any pre-existing defaults. 0536 0537 The section DEFAULT is special. 0538 """ 0539 d = self._defaults.copy() 0540 try: 0541 d.update(self._sections[section]) 0542 except KeyError: 0543 if section != DEFAULTSECT: 0544 raise NoSectionError(section) 0545 # Update with the entry specific variables 0546 if vars: 0547 for key, value in vars.items(): 0548 d[self.optionxform(key)] = value 0549 options = d.keys() 0550 if "__name__" in options: 0551 options.remove("__name__") 0552 if raw: 0553 return [(option, d[option]) 0554 for option in options] 0555 else: 0556 return [(option, self._interpolate(section, option, d[option], d)) 0557 for option in options] 0558 0559 def _interpolate(self, section, option, rawval, vars): 0560 # do the string interpolation 0561 value = rawval 0562 depth = MAX_INTERPOLATION_DEPTH 0563 while depth: # Loop through this until it's done 0564 depth -= 1 0565 if "%(" in value: 0566 value = self._KEYCRE.sub(self._interpolation_replace, value) 0567 try: 0568 value = value % vars 0569 except KeyError, e: 0570 raise InterpolationMissingOptionError( 0571 option, section, rawval, e[0]) 0572 else: 0573 break 0574 if "%(" in value: 0575 raise InterpolationDepthError(option, section, rawval) 0576 return value 0577 0578 _KEYCRE = re.compile(r"%\(([^)]*)\)s|.") 0579 0580 def _interpolation_replace(self, match): 0581 s = match.group(1) 0582 if s is None: 0583 return match.group() 0584 else: 0585 return "%%(%s)s" % self.optionxform(s) 0586 0587 0588 class SafeConfigParser(ConfigParser): 0589 0590 def _interpolate(self, section, option, rawval, vars): 0591 # do the string interpolation 0592 L = [] 0593 self._interpolate_some(option, L, rawval, section, vars, 1) 0594 return ''.join(L) 0595 0596 _interpvar_match = re.compile(r"%\(([^)]+)\)s").match 0597 0598 def _interpolate_some(self, option, accum, rest, section, map, depth): 0599 if depth > MAX_INTERPOLATION_DEPTH: 0600 raise InterpolationDepthError(option, section, rest) 0601 while rest: 0602 p = rest.find("%") 0603 if p < 0: 0604 accum.append(rest) 0605 return 0606 if p > 0: 0607 accum.append(rest[:p]) 0608 rest = rest[p:] 0609 # p is no longer used 0610 c = rest[1:2] 0611 if c == "%": 0612 accum.append("%") 0613 rest = rest[2:] 0614 elif c == "(": 0615 m = self._interpvar_match(rest) 0616 if m is None: 0617 raise InterpolationSyntaxError(option, section, 0618 "bad interpolation variable reference %r" % rest) 0619 var = self.optionxform(m.group(1)) 0620 rest = rest[m.end():] 0621 try: 0622 v = map[var] 0623 except KeyError: 0624 raise InterpolationMissingOptionError( 0625 option, section, rest, var) 0626 if "%" in v: 0627 self._interpolate_some(option, accum, v, 0628 section, map, depth + 1) 0629 else: 0630 accum.append(v) 0631 else: 0632 raise InterpolationSyntaxError( 0633 option, section, 0634 "'%%' must be followed by '%%' or '(', found: %r" % (rest,)) 0635 0636 def set(self, section, option, value): 0637 """Set an option. Extend ConfigParser.set: check for string values.""" 0638 if not isinstance(value, basestring): 0639 raise TypeError("option values must be strings") 0640 ConfigParser.set(self, section, option, value) 0641
Generated by PyXR 0.9.4