ConfigParser.py 22.6 KB
Newer Older
1 2 3 4
"""Configuration file parser.

A setup file consists of sections, lead by a "[section]" header,
and followed by "name: value" entries, with continuations and such in
Barry Warsaw's avatar
Barry Warsaw committed
5 6 7 8
the style of RFC 822.

The option values can contain format strings which refer to other values in
the same section, or values in a special [DEFAULT] section.
9 10 11 12 13 14 15 16 17 18 19 20 21

For example:

    something: %(dir)s/whatever

would resolve the "%(dir)s" to the value of dir.  All reference
expansions are done late, on demand.

Intrinsic defaults can be specified by passing them into the
ConfigParser constructor as a dictionary.

class:

22
ConfigParser -- responsible for parsing a list of
23 24 25 26
                configuration files, and managing the parsed database.

    methods:

27 28 29 30
    __init__(defaults=None)
        create the parser and specify a dictionary of intrinsic defaults.  The
        keys must be strings, the values must be appropriate for %()s string
        interpolation.  Note that `__name__' is always an intrinsic default;
31
        its value is the section's name.
32

33 34
    sections()
        return all the configuration section names, sans DEFAULT
35

36 37 38
    has_section(section)
        return whether the given section exists

39 40 41
    has_option(section, option)
        return whether the given option exists in the given section

42 43
    options(section)
        return list of configuration options for the named section
44

45
    read(filenames)
Guido van Rossum's avatar
Guido van Rossum committed
46 47
        read and parse the list of named configuration files, given by
        name.  A single filename is also allowed.  Non-existing files
Fred Drake's avatar
Fred Drake committed
48
        are ignored.  Return list of successfully read files.
Guido van Rossum's avatar
Guido van Rossum committed
49 50 51 52

    readfp(fp, filename=None)
        read and parse one configuration file, given as a file object.
        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 57 58 59 60
        return a string value for the named option.  All % interpolations are
        expanded in the return values, based on the defaults passed into the
        constructor and the DEFAULT section.  Additional substitutions may be
        provided using the `vars' argument, which must be a dictionary whose
        contents override any pre-existing defaults.
61

62 63
    getint(section, options)
        like get(), but convert value to an integer
64

65 66
    getfloat(section, options)
        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 71
        insensitively defined as 0, false, no, off for False, and 1, true,
        yes, on for True).  Returns False or True.
72

73
    items(section, raw=False, vars=None)
74 75 76
        return a list of tuples with (name, value) for each option
        in the section.

77
    remove_section(section)
Tim Peters's avatar
Tim Peters committed
78
        remove the given file section and all its options
79 80

    remove_option(section, option)
Tim Peters's avatar
Tim Peters committed
81
        remove the given option from the given section
82 83 84 85 86

    set(section, option, value)
        set the given option

    write(fp)
Tim Peters's avatar
Tim Peters committed
87
        write the configuration state in .ini format
88 89
"""

Barry Warsaw's avatar
Barry Warsaw committed
90
import re
91

92 93 94
__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError",
           "InterpolationError", "InterpolationDepthError",
           "InterpolationSyntaxError", "ParsingError",
95 96
           "MissingSectionHeaderError",
           "ConfigParser", "SafeConfigParser", "RawConfigParser",
97
           "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
98

99 100
DEFAULTSECT = "DEFAULT"

101 102
MAX_INTERPOLATION_DEPTH = 10

103

Tim Peters's avatar
Tim Peters committed
104

105
# exception classes
106
class Error(Exception):
107 108
    """Base class for ConfigParser exceptions."""

109
    def __init__(self, msg=''):
110
        self.message = msg
111
        Exception.__init__(self, msg)
112

113
    def __repr__(self):
114
        return self.message
115

116
    __str__ = __repr__
117 118

class NoSectionError(Error):
119 120
    """Raised when no section matches a requested option."""

121
    def __init__(self, section):
122
        Error.__init__(self, 'No section: %r' % (section,))
123
        self.section = section
124 125

class DuplicateSectionError(Error):
126 127
    """Raised when a section is multiply-created."""

128
    def __init__(self, section):
129
        Error.__init__(self, "Section %r already exists" % section)
130
        self.section = section
131 132

class NoOptionError(Error):
133 134
    """A requested option was not found."""

135
    def __init__(self, option, section):
136
        Error.__init__(self, "No option %r in section: %r" %
137 138 139
                       (option, section))
        self.option = option
        self.section = section
140 141

class InterpolationError(Error):
142
    """Base class for interpolation-related exceptions."""
143

144 145
    def __init__(self, option, section, msg):
        Error.__init__(self, msg)
146 147
        self.option = option
        self.section = section
148

149 150 151 152 153 154 155 156 157 158 159 160 161 162
class InterpolationMissingOptionError(InterpolationError):
    """A string substitution required a setting which was not available."""

    def __init__(self, option, section, rawval, reference):
        msg = ("Bad value substitution:\n"
               "\tsection: [%s]\n"
               "\toption : %s\n"
               "\tkey    : %s\n"
               "\trawval : %s\n"
               % (section, option, reference, rawval))
        InterpolationError.__init__(self, option, section, msg)
        self.reference = reference

class InterpolationSyntaxError(InterpolationError):
163 164
    """Raised when the source text into which substitutions are made
    does not conform to the required syntax."""
165

166
class InterpolationDepthError(InterpolationError):
167 168
    """Raised when substitutions are nested too deeply."""

169
    def __init__(self, option, section, rawval):
170 171 172 173 174 175
        msg = ("Value interpolation too deeply recursive:\n"
               "\tsection: [%s]\n"
               "\toption : %s\n"
               "\trawval : %s\n"
               % (section, option, rawval))
        InterpolationError.__init__(self, option, section, msg)
Barry Warsaw's avatar
Barry Warsaw committed
176 177

class ParsingError(Error):
178 179
    """Raised when a configuration file does not follow legal syntax."""

Barry Warsaw's avatar
Barry Warsaw committed
180 181 182 183 184 185 186
    def __init__(self, filename):
        Error.__init__(self, 'File contains parsing errors: %s' % filename)
        self.filename = filename
        self.errors = []

    def append(self, lineno, line):
        self.errors.append((lineno, line))
187
        self.message += '\n\t[line %2d]: %s' % (lineno, line)
Barry Warsaw's avatar
Barry Warsaw committed
188

189
class MissingSectionHeaderError(ParsingError):
190 191
    """Raised when a key-value pair is found before any section header."""

192 193 194
    def __init__(self, filename, lineno, line):
        Error.__init__(
            self,
195
            'File contains no section headers.\nfile: %s, line: %d\n%r' %
196 197 198 199 200
            (filename, lineno, line))
        self.filename = filename
        self.lineno = lineno
        self.line = line

201

Tim Peters's avatar
Tim Peters committed
202

203
class RawConfigParser:
204
    def __init__(self, defaults=None):
205
        self._sections = {}
206 207 208 209
        self._defaults = {}
        if defaults:
            for key, value in defaults.items():
                self._defaults[self.optionxform(key)] = value
210 211

    def defaults(self):
212
        return self._defaults
213 214

    def sections(self):
215
        """Return a list of section names, excluding [DEFAULT]"""
216 217
        # self._sections will never have [DEFAULT] in it
        return self._sections.keys()
218 219

    def add_section(self, section):
220
        """Create a new section in the configuration.
221

222 223 224
        Raise DuplicateSectionError if a section by the specified name
        already exists.
        """
225
        if section in self._sections:
226
            raise DuplicateSectionError(section)
227
        self._sections[section] = {}
228 229

    def has_section(self, section):
230
        """Indicate whether the named section is present in the configuration.
231

232 233
        The DEFAULT section is not acknowledged.
        """
234
        return section in self._sections
235 236

    def options(self, section):
237
        """Return a list of option names for the given section name."""
238
        try:
239
            opts = self._sections[section].copy()
240 241
        except KeyError:
            raise NoSectionError(section)
242
        opts.update(self._defaults)
243
        if '__name__' in opts:
244
            del opts['__name__']
245
        return opts.keys()
246 247

    def read(self, filenames):
Guido van Rossum's avatar
Guido van Rossum committed
248
        """Read and parse a filename or a list of filenames.
Tim Peters's avatar
Tim Peters committed
249

Guido van Rossum's avatar
Guido van Rossum committed
250
        Files that cannot be opened are silently ignored; this is
251
        designed so that you can specify a list of potential
Guido van Rossum's avatar
Guido van Rossum committed
252 253 254 255
        configuration file locations (e.g. current directory, user's
        home directory, systemwide directory), and all existing
        configuration files in the list will be read.  A single
        filename may also be given.
Fred Drake's avatar
Fred Drake committed
256 257

        Return list of successfully read files.
Guido van Rossum's avatar
Guido van Rossum committed
258
        """
259
        if isinstance(filenames, basestring):
260
            filenames = [filenames]
Fred Drake's avatar
Fred Drake committed
261
        read_ok = []
Guido van Rossum's avatar
Guido van Rossum committed
262 263 264 265 266
        for filename in filenames:
            try:
                fp = open(filename)
            except IOError:
                continue
267
            self._read(fp, filename)
268
            fp.close()
Fred Drake's avatar
Fred Drake committed
269 270
            read_ok.append(filename)
        return read_ok
271

Guido van Rossum's avatar
Guido van Rossum committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285
    def readfp(self, fp, filename=None):
        """Like read() but the argument must be a file-like object.

        The `fp' argument must have a `readline' method.  Optional
        second argument is the `filename', which if not given, is
        taken from fp.name.  If fp has no `name' attribute, `<???>' is
        used.

        """
        if filename is None:
            try:
                filename = fp.name
            except AttributeError:
                filename = '<???>'
286
        self._read(fp, filename)
Guido van Rossum's avatar
Guido van Rossum committed
287

288 289 290
    def get(self, section, option):
        opt = self.optionxform(option)
        if section not in self._sections:
291
            if section != DEFAULTSECT:
292
                raise NoSectionError(section)
293 294 295 296 297 298 299 300 301
            if opt in self._defaults:
                return self._defaults[opt]
            else:
                raise NoOptionError(option, section)
        elif opt in self._sections[section]:
            return self._sections[section][opt]
        elif opt in self._defaults:
            return self._defaults[opt]
        else:
302
            raise NoOptionError(option, section)
303

304
    def items(self, section):
305
        try:
306
            d2 = self._sections[section]
307 308 309
        except KeyError:
            if section != DEFAULTSECT:
                raise NoSectionError(section)
310
            d2 = {}
311 312
        d = self._defaults.copy()
        d.update(d2)
313 314
        if "__name__" in d:
            del d["__name__"]
315
        return d.items()
Tim Peters's avatar
Tim Peters committed
316

317
    def _get(self, section, conv, option):
318
        return conv(self.get(section, option))
319 320

    def getint(self, section, option):
321
        return self._get(section, int, option)
322 323

    def getfloat(self, section, option):
324
        return self._get(section, float, option)
325

326 327 328
    _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
                       '0': False, 'no': False, 'false': False, 'off': False}

329
    def getboolean(self, section, option):
Tim Peters's avatar
Tim Peters committed
330
        v = self.get(section, option)
331
        if v.lower() not in self._boolean_states:
332
            raise ValueError, 'Not a boolean: %s' % v
333
        return self._boolean_states[v.lower()]
334

335
    def optionxform(self, optionstr):
336
        return optionstr.lower()
337

338 339
    def has_option(self, section, option):
        """Check for the existence of a given option in a given section."""
340 341
        if not section or section == DEFAULTSECT:
            option = self.optionxform(option)
342 343
            return option in self._defaults
        elif section not in self._sections:
344
            return False
345
        else:
346
            option = self.optionxform(option)
347 348
            return (option in self._sections[section]
                    or option in self._defaults)
349 350 351

    def set(self, section, option, value):
        """Set an option."""
352
        if not section or section == DEFAULTSECT:
353
            sectdict = self._defaults
354 355
        else:
            try:
356
                sectdict = self._sections[section]
357 358
            except KeyError:
                raise NoSectionError(section)
359
        sectdict[self.optionxform(option)] = value
360 361 362

    def write(self, fp):
        """Write an .ini-format representation of the configuration state."""
363
        if self._defaults:
364
            fp.write("[%s]\n" % DEFAULTSECT)
365
            for (key, value) in self._defaults.items():
366
                fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t')))
367
            fp.write("\n")
368
        for section in self._sections:
369
            fp.write("[%s]\n" % section)
370
            for (key, value) in self._sections[section].items():
371 372 373
                if key != "__name__":
                    fp.write("%s = %s\n" %
                             (key, str(value).replace('\n', '\n\t')))
374 375
            fp.write("\n")

376
    def remove_option(self, section, option):
377
        """Remove an option."""
378
        if not section or section == DEFAULTSECT:
379
            sectdict = self._defaults
380 381
        else:
            try:
382
                sectdict = self._sections[section]
383 384
            except KeyError:
                raise NoSectionError(section)
385
        option = self.optionxform(option)
386
        existed = option in sectdict
387
        if existed:
388
            del sectdict[option]
389 390
        return existed

391
    def remove_section(self, section):
392
        """Remove a file section."""
393
        existed = section in self._sections
394
        if existed:
395
            del self._sections[section]
396
        return existed
397

Barry Warsaw's avatar
Barry Warsaw committed
398
    #
399 400
    # Regular expressions for parsing section headers and options.
    #
401
    SECTCRE = re.compile(
Barry Warsaw's avatar
Barry Warsaw committed
402
        r'\['                                 # [
403
        r'(?P<header>[^]]+)'                  # very permissive!
Barry Warsaw's avatar
Barry Warsaw committed
404 405
        r'\]'                                 # ]
        )
406
    OPTCRE = re.compile(
407
        r'(?P<option>[^:=\s][^:=]*)'          # very permissive!
408
        r'\s*(?P<vi>[:=])\s*'                 # any number of space/tab,
Barry Warsaw's avatar
Barry Warsaw committed
409 410 411 412 413 414
                                              # followed by separator
                                              # (either : or =), followed
                                              # by any # space/tab
        r'(?P<value>.*)$'                     # everything up to eol
        )

415
    def _read(self, fp, fpname):
416 417 418 419 420
        """Parse a sectioned setup file.

        The sections in setup file contains a title line at the top,
        indicated by a name in square brackets (`[]'), plus key/value
        options lines, indicated by `name: value' format lines.
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
421
        Continuations are represented by an embedded newline then
422
        leading whitespace.  Blank lines, lines beginning with a '#',
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
423
        and just about everything else are ignored.
424
        """
Barry Warsaw's avatar
Barry Warsaw committed
425
        cursect = None                            # None, or a dictionary
426 427
        optname = None
        lineno = 0
Barry Warsaw's avatar
Barry Warsaw committed
428
        e = None                                  # None, or an exception
429
        while True:
430 431 432 433 434
            line = fp.readline()
            if not line:
                break
            lineno = lineno + 1
            # comment or blank line?
435
            if line.strip() == '' or line[0] in '#;':
436
                continue
437 438
            if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
                # no leading whitespace
439 440
                continue
            # continuation line?
441
            if line[0].isspace() and cursect is not None and optname:
442
                value = line.strip()
443
                if value:
444
                    cursect[optname] = "%s\n%s" % (cursect[optname], value)
Barry Warsaw's avatar
Barry Warsaw committed
445
            # a section header or option header?
446
            else:
Barry Warsaw's avatar
Barry Warsaw committed
447
                # is it a section header?
448
                mo = self.SECTCRE.match(line)
Barry Warsaw's avatar
Barry Warsaw committed
449 450
                if mo:
                    sectname = mo.group('header')
451 452
                    if sectname in self._sections:
                        cursect = self._sections[sectname]
Barry Warsaw's avatar
Barry Warsaw committed
453
                    elif sectname == DEFAULTSECT:
454
                        cursect = self._defaults
Barry Warsaw's avatar
Barry Warsaw committed
455
                    else:
456
                        cursect = {'__name__': sectname}
457
                        self._sections[sectname] = cursect
Barry Warsaw's avatar
Barry Warsaw committed
458 459 460 461
                    # So sections can't start with a continuation line
                    optname = None
                # no section header in the file?
                elif cursect is None:
462
                    raise MissingSectionHeaderError(fpname, lineno, line)
Barry Warsaw's avatar
Barry Warsaw committed
463 464
                # an option line?
                else:
465
                    mo = self.OPTCRE.match(line)
Barry Warsaw's avatar
Barry Warsaw committed
466
                    if mo:
467
                        optname, vi, optval = mo.group('option', 'vi', 'value')
468
                        if vi in ('=', ':') and ';' in optval:
469 470
                            # ';' is a comment delimiter only if it follows
                            # a spacing character
471
                            pos = optval.find(';')
472
                            if pos != -1 and optval[pos-1].isspace():
473
                                optval = optval[:pos]
474
                        optval = optval.strip()
Barry Warsaw's avatar
Barry Warsaw committed
475 476 477
                        # allow empty values
                        if optval == '""':
                            optval = ''
478
                        optname = self.optionxform(optname.rstrip())
479
                        cursect[optname] = optval
Barry Warsaw's avatar
Barry Warsaw committed
480 481 482 483 484 485
                    else:
                        # a non-fatal parsing error occurred.  set up the
                        # exception but keep going. the exception will be
                        # raised at the end of the file and will contain a
                        # list of all bogus lines
                        if not e:
Guido van Rossum's avatar
Guido van Rossum committed
486
                            e = ParsingError(fpname)
487
                        e.append(lineno, repr(line))
Barry Warsaw's avatar
Barry Warsaw committed
488 489 490
        # if any parsing errors occurred, raise an exception
        if e:
            raise e
491 492 493 494


class ConfigParser(RawConfigParser):

495
    def get(self, section, option, raw=False, vars=None):
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
        """Get an option value for a given section.

        All % interpolations are expanded in the return values, based on the
        defaults passed into the constructor, unless the optional argument
        `raw' is true.  Additional substitutions may be provided using the
        `vars' argument, which must be a dictionary whose contents overrides
        any pre-existing defaults.

        The section DEFAULT is special.
        """
        d = self._defaults.copy()
        try:
            d.update(self._sections[section])
        except KeyError:
            if section != DEFAULTSECT:
                raise NoSectionError(section)
        # Update with the entry specific variables
513 514 515
        if vars:
            for key, value in vars.items():
                d[self.optionxform(key)] = value
516 517 518 519 520 521 522 523 524 525 526
        option = self.optionxform(option)
        try:
            value = d[option]
        except KeyError:
            raise NoOptionError(option, section)

        if raw:
            return value
        else:
            return self._interpolate(section, option, value, d)

527
    def items(self, section, raw=False, vars=None):
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
        """Return a list of tuples with (name, value) for each option
        in the section.

        All % interpolations are expanded in the return values, based on the
        defaults passed into the constructor, unless the optional argument
        `raw' is true.  Additional substitutions may be provided using the
        `vars' argument, which must be a dictionary whose contents overrides
        any pre-existing defaults.

        The section DEFAULT is special.
        """
        d = self._defaults.copy()
        try:
            d.update(self._sections[section])
        except KeyError:
            if section != DEFAULTSECT:
                raise NoSectionError(section)
        # Update with the entry specific variables
        if vars:
547 548
            for key, value in vars.items():
                d[self.optionxform(key)] = value
549 550 551
        options = d.keys()
        if "__name__" in options:
            options.remove("__name__")
552
        if raw:
553 554
            return [(option, d[option])
                    for option in options]
555
        else:
556 557
            return [(option, self._interpolate(section, option, d[option], d))
                    for option in options]
558 559 560 561

    def _interpolate(self, section, option, rawval, vars):
        # do the string interpolation
        value = rawval
Tim Peters's avatar
Tim Peters committed
562
        depth = MAX_INTERPOLATION_DEPTH
563 564
        while depth:                    # Loop through this until it's done
            depth -= 1
565
            if "%(" in value:
Fred Drake's avatar
Fred Drake committed
566
                value = self._KEYCRE.sub(self._interpolation_replace, value)
567 568
                try:
                    value = value % vars
569
                except KeyError, e:
570 571
                    raise InterpolationMissingOptionError(
                        option, section, rawval, e[0])
572 573
            else:
                break
574
        if "%(" in value:
575 576
            raise InterpolationDepthError(option, section, rawval)
        return value
577

Fred Drake's avatar
Fred Drake committed
578 579 580 581 582 583 584 585 586
    _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")

    def _interpolation_replace(self, match):
        s = match.group(1)
        if s is None:
            return match.group()
        else:
            return "%%(%s)s" % self.optionxform(s)

587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616

class SafeConfigParser(ConfigParser):

    def _interpolate(self, section, option, rawval, vars):
        # do the string interpolation
        L = []
        self._interpolate_some(option, L, rawval, section, vars, 1)
        return ''.join(L)

    _interpvar_match = re.compile(r"%\(([^)]+)\)s").match

    def _interpolate_some(self, option, accum, rest, section, map, depth):
        if depth > MAX_INTERPOLATION_DEPTH:
            raise InterpolationDepthError(option, section, rest)
        while rest:
            p = rest.find("%")
            if p < 0:
                accum.append(rest)
                return
            if p > 0:
                accum.append(rest[:p])
                rest = rest[p:]
            # p is no longer used
            c = rest[1:2]
            if c == "%":
                accum.append("%")
                rest = rest[2:]
            elif c == "(":
                m = self._interpvar_match(rest)
                if m is None:
617 618
                    raise InterpolationSyntaxError(option, section,
                        "bad interpolation variable reference %r" % rest)
Fred Drake's avatar
Fred Drake committed
619
                var = self.optionxform(m.group(1))
620 621 622 623
                rest = rest[m.end():]
                try:
                    v = map[var]
                except KeyError:
624 625
                    raise InterpolationMissingOptionError(
                        option, section, rest, var)
626 627 628 629 630 631 632
                if "%" in v:
                    self._interpolate_some(option, accum, v,
                                           section, map, depth + 1)
                else:
                    accum.append(v)
            else:
                raise InterpolationSyntaxError(
633
                    option, section,
634
                    "'%%' must be followed by '%%' or '(', found: %r" % (rest,))
635 636 637 638 639 640

    def set(self, section, option, value):
        """Set an option.  Extend ConfigParser.set: check for string values."""
        if not isinstance(value, basestring):
            raise TypeError("option values must be strings")
        ConfigParser.set(self, section, option, value)