ConfigParser.py 21.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 22 23 24 25 26

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:

ConfigParser -- responsible for for parsing a list of
                configuration files, and managing the parsed database.

    methods:

27 28 29 30 31
    __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;
        it's 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 48 49 50 51 52
        read and parse the list of named configuration files, given by
        name.  A single filename is also allowed.  Non-existing files
        are ignored.

    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
           "MissingSectionHeaderError", "ConfigParser", "SafeConfigParser",
96
           "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
97

98 99
DEFAULTSECT = "DEFAULT"

100 101
MAX_INTERPOLATION_DEPTH = 10

102

Tim Peters's avatar
Tim Peters committed
103

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

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

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

115
    __str__ = __repr__
116 117

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

120
    def __init__(self, section):
121
        Error.__init__(self, 'No section: ' + `section`)
122
        self.section = section
123 124

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

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

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

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

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

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

148 149 150 151 152 153 154 155 156 157 158 159 160 161
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):
162 163
    """Raised when the source text into which substitutions are made
    does not conform to the required syntax."""
164

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

168
    def __init__(self, option, section, rawval):
169 170 171 172 173 174
        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
175 176

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

Barry Warsaw's avatar
Barry Warsaw committed
179 180 181 182 183 184 185
    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))
186
        self.message += '\n\t[line %2d]: %s' % (lineno, line)
Barry Warsaw's avatar
Barry Warsaw committed
187

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

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

200

Tim Peters's avatar
Tim Peters committed
201

202
class RawConfigParser:
203
    def __init__(self, defaults=None):
204
        self._sections = {}
205
        if defaults is None:
206
            self._defaults = {}
207
        else:
208
            self._defaults = defaults
209 210

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

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

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

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

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

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

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

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

Guido van Rossum's avatar
Guido van Rossum committed
249
        Files that cannot be opened are silently ignored; this is
250
        designed so that you can specify a list of potential
Guido van Rossum's avatar
Guido van Rossum committed
251 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.
        """
256
        if isinstance(filenames, basestring):
257
            filenames = [filenames]
Guido van Rossum's avatar
Guido van Rossum committed
258 259 260 261 262
        for filename in filenames:
            try:
                fp = open(filename)
            except IOError:
                continue
263
            self._read(fp, filename)
264
            fp.close()
265

Guido van Rossum's avatar
Guido van Rossum committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279
    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 = '<???>'
280
        self._read(fp, filename)
Guido van Rossum's avatar
Guido van Rossum committed
281

282 283 284
    def get(self, section, option):
        opt = self.optionxform(option)
        if section not in self._sections:
285
            if section != DEFAULTSECT:
286
                raise NoSectionError(section)
287 288 289 290 291 292 293 294 295
            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:
296
            raise NoOptionError(option, section)
297

298
    def items(self, section):
299
        try:
300
            d2 = self._sections[section]
301 302 303
        except KeyError:
            if section != DEFAULTSECT:
                raise NoSectionError(section)
304
            d2 = {}
305 306
        d = self._defaults.copy()
        d.update(d2)
307 308
        if "__name__" in d:
            del d["__name__"]
309
        return d.items()
Tim Peters's avatar
Tim Peters committed
310

311
    def _get(self, section, conv, option):
312
        return conv(self.get(section, option))
313 314

    def getint(self, section, option):
315
        return self._get(section, int, option)
316 317

    def getfloat(self, section, option):
318
        return self._get(section, float, option)
319

320 321 322
    _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
                       '0': False, 'no': False, 'false': False, 'off': False}

323
    def getboolean(self, section, option):
Tim Peters's avatar
Tim Peters committed
324
        v = self.get(section, option)
325
        if v.lower() not in self._boolean_states:
326
            raise ValueError, 'Not a boolean: %s' % v
327
        return self._boolean_states[v.lower()]
328

329
    def optionxform(self, optionstr):
330
        return optionstr.lower()
331

332 333
    def has_option(self, section, option):
        """Check for the existence of a given option in a given section."""
334 335
        if not section or section == DEFAULTSECT:
            option = self.optionxform(option)
336 337
            return option in self._defaults
        elif section not in self._sections:
338
            return False
339
        else:
340
            option = self.optionxform(option)
341 342
            return (option in self._sections[section]
                    or option in self._defaults)
343 344 345

    def set(self, section, option, value):
        """Set an option."""
346
        if not section or section == DEFAULTSECT:
347
            sectdict = self._defaults
348 349
        else:
            try:
350
                sectdict = self._sections[section]
351 352
            except KeyError:
                raise NoSectionError(section)
353
        sectdict[self.optionxform(option)] = value
354 355 356

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

370
    def remove_option(self, section, option):
371
        """Remove an option."""
372
        if not section or section == DEFAULTSECT:
373
            sectdict = self._defaults
374 375
        else:
            try:
376
                sectdict = self._sections[section]
377 378
            except KeyError:
                raise NoSectionError(section)
379
        option = self.optionxform(option)
380
        existed = option in sectdict
381
        if existed:
382
            del sectdict[option]
383 384
        return existed

385
    def remove_section(self, section):
386
        """Remove a file section."""
387
        existed = section in self._sections
388
        if existed:
389
            del self._sections[section]
390
        return existed
391

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

409
    def _read(self, fp, fpname):
410 411 412 413 414
        """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
415
        Continuations are represented by an embedded newline then
416
        leading whitespace.  Blank lines, lines beginning with a '#',
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
417
        and just about everything else are ignored.
418
        """
Barry Warsaw's avatar
Barry Warsaw committed
419
        cursect = None                            # None, or a dictionary
420 421
        optname = None
        lineno = 0
Barry Warsaw's avatar
Barry Warsaw committed
422
        e = None                                  # None, or an exception
423
        while True:
424 425 426 427 428
            line = fp.readline()
            if not line:
                break
            lineno = lineno + 1
            # comment or blank line?
429
            if line.strip() == '' or line[0] in '#;':
430
                continue
431 432
            if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
                # no leading whitespace
433 434
                continue
            # continuation line?
435
            if line[0].isspace() and cursect is not None and optname:
436
                value = line.strip()
437
                if value:
438
                    cursect[optname] = "%s\n%s" % (cursect[optname], value)
Barry Warsaw's avatar
Barry Warsaw committed
439
            # a section header or option header?
440
            else:
Barry Warsaw's avatar
Barry Warsaw committed
441
                # is it a section header?
442
                mo = self.SECTCRE.match(line)
Barry Warsaw's avatar
Barry Warsaw committed
443 444
                if mo:
                    sectname = mo.group('header')
445 446
                    if sectname in self._sections:
                        cursect = self._sections[sectname]
Barry Warsaw's avatar
Barry Warsaw committed
447
                    elif sectname == DEFAULTSECT:
448
                        cursect = self._defaults
Barry Warsaw's avatar
Barry Warsaw committed
449
                    else:
450
                        cursect = {'__name__': sectname}
451
                        self._sections[sectname] = cursect
Barry Warsaw's avatar
Barry Warsaw committed
452 453 454 455
                    # So sections can't start with a continuation line
                    optname = None
                # no section header in the file?
                elif cursect is None:
Guido van Rossum's avatar
Guido van Rossum committed
456
                    raise MissingSectionHeaderError(fpname, lineno, `line`)
Barry Warsaw's avatar
Barry Warsaw committed
457 458
                # an option line?
                else:
459
                    mo = self.OPTCRE.match(line)
Barry Warsaw's avatar
Barry Warsaw committed
460
                    if mo:
461
                        optname, vi, optval = mo.group('option', 'vi', 'value')
462
                        if vi in ('=', ':') and ';' in optval:
463 464
                            # ';' is a comment delimiter only if it follows
                            # a spacing character
465
                            pos = optval.find(';')
466
                            if pos != -1 and optval[pos-1].isspace():
467
                                optval = optval[:pos]
468
                        optval = optval.strip()
Barry Warsaw's avatar
Barry Warsaw committed
469 470 471
                        # allow empty values
                        if optval == '""':
                            optval = ''
472
                        optname = self.optionxform(optname.rstrip())
473
                        cursect[optname] = optval
Barry Warsaw's avatar
Barry Warsaw committed
474 475 476 477 478 479
                    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
480
                            e = ParsingError(fpname)
Barry Warsaw's avatar
Barry Warsaw committed
481 482 483 484
                        e.append(lineno, `line`)
        # if any parsing errors occurred, raise an exception
        if e:
            raise e
485 486 487 488


class ConfigParser(RawConfigParser):

489
    def get(self, section, option, raw=False, vars=None):
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
        """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
        if vars is not None:
            d.update(vars)
        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)

520
    def items(self, section, raw=False, vars=None):
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
        """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:
            d.update(vars)
541 542 543
        options = d.keys()
        if "__name__" in options:
            options.remove("__name__")
544
        if raw:
545
            for option in options:
546 547
                yield (option, d[option])
        else:
548
            for option in options:
549 550 551 552 553 554
                yield (option,
                       self._interpolate(section, option, d[option], d))

    def _interpolate(self, section, option, rawval, vars):
        # do the string interpolation
        value = rawval
Tim Peters's avatar
Tim Peters committed
555
        depth = MAX_INTERPOLATION_DEPTH
556 557 558 559 560
        while depth:                    # Loop through this until it's done
            depth -= 1
            if value.find("%(") != -1:
                try:
                    value = value % vars
561
                except KeyError, e:
562 563
                    raise InterpolationMissingOptionError(
                        option, section, rawval, e[0])
564 565 566 567 568
            else:
                break
        if value.find("%(") != -1:
            raise InterpolationDepthError(option, section, rawval)
        return value
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599


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:
600 601
                    raise InterpolationSyntaxError(option, section,
                        "bad interpolation variable reference %r" % rest)
602 603 604 605 606
                var = m.group(1)
                rest = rest[m.end():]
                try:
                    v = map[var]
                except KeyError:
607 608
                    raise InterpolationMissingOptionError(
                        option, section, rest, var)
609 610 611 612 613 614 615
                if "%" in v:
                    self._interpolate_some(option, accum, v,
                                           section, map, depth + 1)
                else:
                    accum.append(v)
            else:
                raise InterpolationSyntaxError(
616
                    option, section,
617
                    "'%' must be followed by '%' or '(', found: " + `rest`)