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