ConfigParser.py 16.8 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 46 47
    has_option(section, option)
        return whether the given section has the given option

48
    read(filenames)
Guido van Rossum's avatar
Guido van Rossum committed
49 50 51 52 53 54 55
        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
56
        messages (if fp has no `name' attribute, the string `<???>' is used).
57

58 59 60 61 62 63
    get(section, option, raw=0, vars=None)
        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.
64

65 66
    getint(section, options)
        like get(), but convert value to an integer
67

68 69
    getfloat(section, options)
        like get(), but convert value to a float
70

71 72 73
    getboolean(section, options)
        like get(), but convert value to a boolean (currently defined as 0 or
        1, only)
74 75

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

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

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

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

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

92 93 94 95 96
__all__ = ["NoSectionError","DuplicateSectionError","NoOptionError",
           "InterpolationError","InterpolationDepthError","ParsingError",
           "MissingSectionHeaderError","ConfigParser",
           "MAX_INTERPOLATION_DEPTH"]

97 98
DEFAULTSECT = "DEFAULT"

99 100
MAX_INTERPOLATION_DEPTH = 10

101

Tim Peters's avatar
Tim Peters committed
102

103
# exception classes
104
class Error(Exception):
105
    def __init__(self, msg=''):
Barry Warsaw's avatar
Barry Warsaw committed
106
        self._msg = msg
107
        Exception.__init__(self, msg)
108
    def __repr__(self):
Barry Warsaw's avatar
Barry Warsaw committed
109
        return self._msg
110
    __str__ = __repr__
111 112 113

class NoSectionError(Error):
    def __init__(self, section):
114 115
        Error.__init__(self, 'No section: %s' % section)
        self.section = section
116 117 118

class DuplicateSectionError(Error):
    def __init__(self, section):
119 120
        Error.__init__(self, "Section %s already exists" % section)
        self.section = section
121 122 123

class NoOptionError(Error):
    def __init__(self, option, section):
124 125 126 127
        Error.__init__(self, "No option `%s' in section: %s" %
                       (option, section))
        self.option = option
        self.section = section
128 129

class InterpolationError(Error):
130
    def __init__(self, reference, option, section, rawval):
131
        Error.__init__(self,
132 133 134 135 136 137
                       "Bad value substitution:\n"
                       "\tsection: [%s]\n"
                       "\toption : %s\n"
                       "\tkey    : %s\n"
                       "\trawval : %s\n"
                       % (section, option, reference, rawval))
138 139 140
        self.reference = reference
        self.option = option
        self.section = section
141

142 143 144 145 146 147 148 149 150 151
class InterpolationDepthError(Error):
    def __init__(self, option, section, rawval):
        Error.__init__(self,
                       "Value interpolation too deeply recursive:\n"
                       "\tsection: [%s]\n"
                       "\toption : %s\n"
                       "\trawval : %s\n"
                       % (section, option, rawval))
        self.option = option
        self.section = section
Barry Warsaw's avatar
Barry Warsaw committed
152 153 154 155 156 157 158 159 160 161 162

class ParsingError(Error):
    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))
        self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)

163 164 165 166 167 168 169 170 171 172
class MissingSectionHeaderError(ParsingError):
    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

173

Tim Peters's avatar
Tim Peters committed
174

175 176
class ConfigParser:
    def __init__(self, defaults=None):
177 178 179 180 181
        self.__sections = {}
        if defaults is None:
            self.__defaults = {}
        else:
            self.__defaults = defaults
182 183

    def defaults(self):
184
        return self.__defaults
185 186

    def sections(self):
187 188 189
        """Return a list of section names, excluding [DEFAULT]"""
        # self.__sections will never have [DEFAULT] in it
        return self.__sections.keys()
190 191

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

194 195 196 197 198 199
        Raise DuplicateSectionError if a section by the specified name
        already exists.
        """
        if self.__sections.has_key(section):
            raise DuplicateSectionError(section)
        self.__sections[section] = {}
200 201

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

204 205
        The DEFAULT section is not acknowledged.
        """
206
        return section in self.sections()
207 208

    def options(self, section):
209
        """Return a list of option names for the given section name."""
210 211 212 213 214
        try:
            opts = self.__sections[section].copy()
        except KeyError:
            raise NoSectionError(section)
        opts.update(self.__defaults)
215 216
        if opts.has_key('__name__'):
            del opts['__name__']
217
        return opts.keys()
218

219 220
    def has_option(self, section, option):
        """Return whether the given section has the given option."""
221
        return option in self.options(section)
222

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

Guido van Rossum's avatar
Guido van Rossum committed
226
        Files that cannot be opened are silently ignored; this is
227
        designed so that you can specify a list of potential
Guido van Rossum's avatar
Guido van Rossum committed
228 229 230 231 232
        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
233
        if type(filenames) in [type(''), type(u'')]:
234
            filenames = [filenames]
Guido van Rossum's avatar
Guido van Rossum committed
235 236 237 238 239 240
        for filename in filenames:
            try:
                fp = open(filename)
            except IOError:
                continue
            self.__read(fp, filename)
241
            fp.close()
242

Guido van Rossum's avatar
Guido van Rossum committed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    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 = '<???>'
        self.__read(fp, filename)

259
    def get(self, section, option, raw=0, vars=None):
260 261
        """Get an option value for a given section.

262 263 264 265 266
        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.
267 268 269 270 271 272 273 274 275 276 277 278

        The section DEFAULT is special.
        """
        try:
            sectdict = self.__sections[section].copy()
        except KeyError:
            if section == DEFAULTSECT:
                sectdict = {}
            else:
                raise NoSectionError(section)
        d = self.__defaults.copy()
        d.update(sectdict)
279 280 281
        # Update with the entry specific variables
        if vars:
            d.update(vars)
282
        option = self.optionxform(option)
283 284 285 286
        try:
            rawval = d[option]
        except KeyError:
            raise NoOptionError(option, section)
287

288 289
        if raw:
            return rawval
290

291
        # do the string interpolation
292
        value = rawval                  # Make it a pretty variable name
Tim Peters's avatar
Tim Peters committed
293
        depth = 0
294 295
        while depth < 10:               # Loop through this until it's done
            depth = depth + 1
296
            if value.find("%(") >= 0:
297 298 299 300 301
                try:
                    value = value % d
                except KeyError, key:
                    raise InterpolationError(key, option, section, rawval)
            else:
302 303 304 305
                break
        if value.find("%(") >= 0:
            raise InterpolationDepthError(option, section, rawval)
        return value
Tim Peters's avatar
Tim Peters committed
306

307
    def __get(self, section, conv, option):
308
        return conv(self.get(section, option))
309 310

    def getint(self, section, option):
311
        return self.__get(section, string.atoi, option)
312 313

    def getfloat(self, section, option):
314
        return self.__get(section, string.atof, option)
315 316

    def getboolean(self, section, option):
317
        v = self.get(section, option)
318
        val = int(v)
319 320 321
        if val not in (0, 1):
            raise ValueError, 'Not a boolean: %s' % v
        return val
322

323
    def optionxform(self, optionstr):
324
        return optionstr.lower()
325

326 327 328 329 330 331 332
    def has_option(self, section, option):
        """Check for the existence of a given option in a given section."""
        if not section or section == "DEFAULT":
            return self.__defaults.has_key(option)
        elif not self.has_section(section):
            return 0
        else:
333
            option = self.optionxform(option)
334 335 336 337 338 339 340 341 342 343 344
            return self.__sections[section].has_key(option)

    def set(self, section, option, value):
        """Set an option."""
        if not section or section == "DEFAULT":
            sectdict = self.__defaults
        else:
            try:
                sectdict = self.__sections[section]
            except KeyError:
                raise NoSectionError(section)
345
        option = self.optionxform(option)
346 347 348 349 350 351
        sectdict[option] = value

    def write(self, fp):
        """Write an .ini-format representation of the configuration state."""
        if self.__defaults:
            fp.write("[DEFAULT]\n")
352 353
            for (key, value) in self.__defaults.items():
                fp.write("%s = %s\n" % (key, value))
354 355 356 357
            fp.write("\n")
        for section in self.sections():
            fp.write("[" + section + "]\n")
            sectdict = self.__sections[section]
358
            for (key, value) in sectdict.items():
359 360
                if key == "__name__":
                    continue
361
                fp.write("%s = %s\n" % (key, value))
362 363
            fp.write("\n")

364
    def remove_option(self, section, option):
365 366 367 368 369 370 371 372
        """Remove an option."""
        if not section or section == "DEFAULT":
            sectdict = self.__defaults
        else:
            try:
                sectdict = self.__sections[section]
            except KeyError:
                raise NoSectionError(section)
373
        option = self.optionxform(option)
374
        existed = sectdict.has_key(option)
375
        if existed:
376
            del sectdict[option]
377 378
        return existed

379
    def remove_section(self, section):
380 381 382 383 384 385 386
        """Remove a file section."""
        if self.__sections.has_key(section):
            del self.__sections[section]
            return 1
        else:
            return 0

Barry Warsaw's avatar
Barry Warsaw committed
387 388 389 390
    #
    # Regular expressions for parsing section headers and options.  Note a
    # slight semantic change from the previous version, because of the use
    # of \w, _ is allowed in section header names.
391
    SECTCRE = re.compile(
Barry Warsaw's avatar
Barry Warsaw committed
392
        r'\['                                 # [
393
        r'(?P<header>[^]]+)'                  # very permissive!
Barry Warsaw's avatar
Barry Warsaw committed
394 395
        r'\]'                                 # ]
        )
396
    OPTCRE = re.compile(
397
        r'(?P<option>[]\-[\w_.*,(){}]+)'      # a lot of stuff found by IvL
398
        r'[ \t]*(?P<vi>[:=])[ \t]*'           # any number of space/tab,
Barry Warsaw's avatar
Barry Warsaw committed
399 400 401 402 403 404
                                              # followed by separator
                                              # (either : or =), followed
                                              # by any # space/tab
        r'(?P<value>.*)$'                     # everything up to eol
        )

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