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