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