~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/configparser.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Configuration file parser.
 
2
 
 
3
A setup file consists of sections, lead by a "[section]" header,
 
4
and followed by "name: value" entries, with continuations and such in
 
5
the style of RFC 822.
 
6
 
 
7
The option values can contain format strings which refer to other values in
 
8
the same section, or values in a special [DEFAULT] section.
 
9
 
 
10
For example:
 
11
 
 
12
    something: %(dir)s/whatever
 
13
 
 
14
would resolve the "%(dir)s" to the value of dir.  All reference
 
15
expansions are done late, on demand.
 
16
 
 
17
Intrinsic defaults can be specified by passing them into the
 
18
ConfigParser constructor as a dictionary.
 
19
 
 
20
class:
 
21
 
 
22
ConfigParser -- 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
 
 
90
try:
 
91
    from collections import OrderedDict as _default_dict
 
92
except ImportError:
 
93
    # fallback for setup.py which hasn't yet built _collections
 
94
    _default_dict = dict
 
95
 
 
96
import 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
 
 
105
DEFAULTSECT = "DEFAULT"
 
106
 
 
107
MAX_INTERPOLATION_DEPTH = 10
 
108
 
 
109
 
 
110
 
 
111
# exception classes
 
112
class 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
 
 
139
class 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
 
 
146
class 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
 
 
153
class 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
 
 
162
class 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
 
 
170
class 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
 
 
183
class InterpolationSyntaxError(InterpolationError):
 
184
    """Raised when the source text into which substitutions are made
 
185
    does not conform to the required syntax."""
 
186
 
 
187
class 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
 
 
198
class 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
 
 
210
class 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
 
 
223
class RawConfigParser:
 
224
    def __init__(self, defaults=None, dict_type=_default_dict):
 
225
        self._dict = dict_type
 
226
        self._sections = self._dict()
 
227
        self._defaults = self._dict()
 
228
        if defaults:
 
229
            for key, value in defaults.items():
 
230
                self._defaults[self.optionxform(key)] = value
 
231
 
 
232
    def defaults(self):
 
233
        return self._defaults
 
234
 
 
235
    def sections(self):
 
236
        """Return a list of section names, excluding [DEFAULT]"""
 
237
        # self._sections will never have [DEFAULT] in it
 
238
        return list(self._sections.keys())
 
239
 
 
240
    def add_section(self, section):
 
241
        """Create a new section in the configuration.
 
242
 
 
243
        Raise DuplicateSectionError if a section by the specified name
 
244
        already exists. Raise ValueError if name is DEFAULT or any of it's
 
245
        case-insensitive variants.
 
246
        """
 
247
        if section.lower() == "default":
 
248
            raise ValueError('Invalid section name: %s' % section)
 
249
 
 
250
        if section in self._sections:
 
251
            raise DuplicateSectionError(section)
 
252
        self._sections[section] = self._dict()
 
253
 
 
254
    def has_section(self, section):
 
255
        """Indicate whether the named section is present in the configuration.
 
256
 
 
257
        The DEFAULT section is not acknowledged.
 
258
        """
 
259
        return section in self._sections
 
260
 
 
261
    def options(self, section):
 
262
        """Return a list of option names for the given section name."""
 
263
        try:
 
264
            opts = self._sections[section].copy()
 
265
        except KeyError:
 
266
            raise NoSectionError(section)
 
267
        opts.update(self._defaults)
 
268
        if '__name__' in opts:
 
269
            del opts['__name__']
 
270
        return list(opts.keys())
 
271
 
 
272
    def read(self, filenames):
 
273
        """Read and parse a filename or a list of filenames.
 
274
 
 
275
        Files that cannot be opened are silently ignored; this is
 
276
        designed so that you can specify a list of potential
 
277
        configuration file locations (e.g. current directory, user's
 
278
        home directory, systemwide directory), and all existing
 
279
        configuration files in the list will be read.  A single
 
280
        filename may also be given.
 
281
 
 
282
        Return list of successfully read files.
 
283
        """
 
284
        if isinstance(filenames, str):
 
285
            filenames = [filenames]
 
286
        read_ok = []
 
287
        for filename in filenames:
 
288
            try:
 
289
                fp = open(filename)
 
290
            except IOError:
 
291
                continue
 
292
            self._read(fp, filename)
 
293
            fp.close()
 
294
            read_ok.append(filename)
 
295
        return read_ok
 
296
 
 
297
    def readfp(self, fp, filename=None):
 
298
        """Like read() but the argument must be a file-like object.
 
299
 
 
300
        The `fp' argument must have a `readline' method.  Optional
 
301
        second argument is the `filename', which if not given, is
 
302
        taken from fp.name.  If fp has no `name' attribute, `<???>' is
 
303
        used.
 
304
 
 
305
        """
 
306
        if filename is None:
 
307
            try:
 
308
                filename = fp.name
 
309
            except AttributeError:
 
310
                filename = '<???>'
 
311
        self._read(fp, filename)
 
312
 
 
313
    def get(self, section, option):
 
314
        opt = self.optionxform(option)
 
315
        if section not in self._sections:
 
316
            if section != DEFAULTSECT:
 
317
                raise NoSectionError(section)
 
318
            if opt in self._defaults:
 
319
                return self._defaults[opt]
 
320
            else:
 
321
                raise NoOptionError(option, section)
 
322
        elif opt in self._sections[section]:
 
323
            return self._sections[section][opt]
 
324
        elif opt in self._defaults:
 
325
            return self._defaults[opt]
 
326
        else:
 
327
            raise NoOptionError(option, section)
 
328
 
 
329
    def items(self, section):
 
330
        try:
 
331
            d2 = self._sections[section]
 
332
        except KeyError:
 
333
            if section != DEFAULTSECT:
 
334
                raise NoSectionError(section)
 
335
            d2 = self._dict()
 
336
        d = self._defaults.copy()
 
337
        d.update(d2)
 
338
        if "__name__" in d:
 
339
            del d["__name__"]
 
340
        return d.items()
 
341
 
 
342
    def _get(self, section, conv, option):
 
343
        return conv(self.get(section, option))
 
344
 
 
345
    def getint(self, section, option):
 
346
        return self._get(section, int, option)
 
347
 
 
348
    def getfloat(self, section, option):
 
349
        return self._get(section, float, option)
 
350
 
 
351
    _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
 
352
                       '0': False, 'no': False, 'false': False, 'off': False}
 
353
 
 
354
    def getboolean(self, section, option):
 
355
        v = self.get(section, option)
 
356
        if v.lower() not in self._boolean_states:
 
357
            raise ValueError('Not a boolean: %s' % v)
 
358
        return self._boolean_states[v.lower()]
 
359
 
 
360
    def optionxform(self, optionstr):
 
361
        return optionstr.lower()
 
362
 
 
363
    def has_option(self, section, option):
 
364
        """Check for the existence of a given option in a given section."""
 
365
        if not section or section == DEFAULTSECT:
 
366
            option = self.optionxform(option)
 
367
            return option in self._defaults
 
368
        elif section not in self._sections:
 
369
            return False
 
370
        else:
 
371
            option = self.optionxform(option)
 
372
            return (option in self._sections[section]
 
373
                    or option in self._defaults)
 
374
 
 
375
    def set(self, section, option, value):
 
376
        """Set an option."""
 
377
        if not section or section == DEFAULTSECT:
 
378
            sectdict = self._defaults
 
379
        else:
 
380
            try:
 
381
                sectdict = self._sections[section]
 
382
            except KeyError:
 
383
                raise NoSectionError(section)
 
384
        sectdict[self.optionxform(option)] = value
 
385
 
 
386
    def write(self, fp):
 
387
        """Write an .ini-format representation of the configuration state."""
 
388
        if self._defaults:
 
389
            fp.write("[%s]\n" % DEFAULTSECT)
 
390
            for (key, value) in self._defaults.items():
 
391
                fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t')))
 
392
            fp.write("\n")
 
393
        for section in self._sections:
 
394
            fp.write("[%s]\n" % section)
 
395
            for (key, value) in self._sections[section].items():
 
396
                if key != "__name__":
 
397
                    fp.write("%s = %s\n" %
 
398
                             (key, str(value).replace('\n', '\n\t')))
 
399
            fp.write("\n")
 
400
 
 
401
    def remove_option(self, section, option):
 
402
        """Remove an option."""
 
403
        if not section or section == DEFAULTSECT:
 
404
            sectdict = self._defaults
 
405
        else:
 
406
            try:
 
407
                sectdict = self._sections[section]
 
408
            except KeyError:
 
409
                raise NoSectionError(section)
 
410
        option = self.optionxform(option)
 
411
        existed = option in sectdict
 
412
        if existed:
 
413
            del sectdict[option]
 
414
        return existed
 
415
 
 
416
    def remove_section(self, section):
 
417
        """Remove a file section."""
 
418
        existed = section in self._sections
 
419
        if existed:
 
420
            del self._sections[section]
 
421
        return existed
 
422
 
 
423
    #
 
424
    # Regular expressions for parsing section headers and options.
 
425
    #
 
426
    SECTCRE = re.compile(
 
427
        r'\['                                 # [
 
428
        r'(?P<header>[^]]+)'                  # very permissive!
 
429
        r'\]'                                 # ]
 
430
        )
 
431
    OPTCRE = re.compile(
 
432
        r'(?P<option>[^:=\s][^:=]*)'          # very permissive!
 
433
        r'\s*(?P<vi>[:=])\s*'                 # any number of space/tab,
 
434
                                              # followed by separator
 
435
                                              # (either : or =), followed
 
436
                                              # by any # space/tab
 
437
        r'(?P<value>.*)$'                     # everything up to eol
 
438
        )
 
439
 
 
440
    def _read(self, fp, fpname):
 
441
        """Parse a sectioned setup file.
 
442
 
 
443
        The sections in setup file contains a title line at the top,
 
444
        indicated by a name in square brackets (`[]'), plus key/value
 
445
        options lines, indicated by `name: value' format lines.
 
446
        Continuations are represented by an embedded newline then
 
447
        leading whitespace.  Blank lines, lines beginning with a '#',
 
448
        and just about everything else are ignored.
 
449
        """
 
450
        cursect = None                            # None, or a dictionary
 
451
        optname = None
 
452
        lineno = 0
 
453
        e = None                                  # None, or an exception
 
454
        while True:
 
455
            line = fp.readline()
 
456
            if not line:
 
457
                break
 
458
            lineno = lineno + 1
 
459
            # comment or blank line?
 
460
            if line.strip() == '' or line[0] in '#;':
 
461
                continue
 
462
            if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
 
463
                # no leading whitespace
 
464
                continue
 
465
            # continuation line?
 
466
            if line[0].isspace() and cursect is not None and optname:
 
467
                value = line.strip()
 
468
                if value:
 
469
                    cursect[optname] = "%s\n%s" % (cursect[optname], value)
 
470
            # a section header or option header?
 
471
            else:
 
472
                # is it a section header?
 
473
                mo = self.SECTCRE.match(line)
 
474
                if mo:
 
475
                    sectname = mo.group('header')
 
476
                    if sectname in self._sections:
 
477
                        cursect = self._sections[sectname]
 
478
                    elif sectname == DEFAULTSECT:
 
479
                        cursect = self._defaults
 
480
                    else:
 
481
                        cursect = self._dict()
 
482
                        cursect['__name__'] = sectname
 
483
                        self._sections[sectname] = cursect
 
484
                    # So sections can't start with a continuation line
 
485
                    optname = None
 
486
                # no section header in the file?
 
487
                elif cursect is None:
 
488
                    raise MissingSectionHeaderError(fpname, lineno, line)
 
489
                # an option line?
 
490
                else:
 
491
                    mo = self.OPTCRE.match(line)
 
492
                    if mo:
 
493
                        optname, vi, optval = mo.group('option', 'vi', 'value')
 
494
                        if vi in ('=', ':') and ';' in optval:
 
495
                            # ';' is a comment delimiter only if it follows
 
496
                            # a spacing character
 
497
                            pos = optval.find(';')
 
498
                            if pos != -1 and optval[pos-1].isspace():
 
499
                                optval = optval[:pos]
 
500
                        optval = optval.strip()
 
501
                        # allow empty values
 
502
                        if optval == '""':
 
503
                            optval = ''
 
504
                        optname = self.optionxform(optname.rstrip())
 
505
                        cursect[optname] = optval
 
506
                    else:
 
507
                        # a non-fatal parsing error occurred.  set up the
 
508
                        # exception but keep going. the exception will be
 
509
                        # raised at the end of the file and will contain a
 
510
                        # list of all bogus lines
 
511
                        if not e:
 
512
                            e = ParsingError(fpname)
 
513
                        e.append(lineno, repr(line))
 
514
        # if any parsing errors occurred, raise an exception
 
515
        if e:
 
516
            raise e
 
517
 
 
518
 
 
519
class ConfigParser(RawConfigParser):
 
520
 
 
521
    def get(self, section, option, raw=False, vars=None):
 
522
        """Get an option value for a given section.
 
523
 
 
524
        All % interpolations are expanded in the return values, based on the
 
525
        defaults passed into the constructor, unless the optional argument
 
526
        `raw' is true.  Additional substitutions may be provided using the
 
527
        `vars' argument, which must be a dictionary whose contents overrides
 
528
        any pre-existing defaults.
 
529
 
 
530
        The section DEFAULT is special.
 
531
        """
 
532
        d = self._defaults.copy()
 
533
        try:
 
534
            d.update(self._sections[section])
 
535
        except KeyError:
 
536
            if section != DEFAULTSECT:
 
537
                raise NoSectionError(section)
 
538
        # Update with the entry specific variables
 
539
        if vars:
 
540
            for key, value in vars.items():
 
541
                d[self.optionxform(key)] = value
 
542
        option = self.optionxform(option)
 
543
        try:
 
544
            value = d[option]
 
545
        except KeyError:
 
546
            raise NoOptionError(option, section)
 
547
 
 
548
        if raw:
 
549
            return value
 
550
        else:
 
551
            return self._interpolate(section, option, value, d)
 
552
 
 
553
    def items(self, section, raw=False, vars=None):
 
554
        """Return a list of tuples with (name, value) for each option
 
555
        in the section.
 
556
 
 
557
        All % interpolations are expanded in the return values, based on the
 
558
        defaults passed into the constructor, unless the optional argument
 
559
        `raw' is true.  Additional substitutions may be provided using the
 
560
        `vars' argument, which must be a dictionary whose contents overrides
 
561
        any pre-existing defaults.
 
562
 
 
563
        The section DEFAULT is special.
 
564
        """
 
565
        d = self._defaults.copy()
 
566
        try:
 
567
            d.update(self._sections[section])
 
568
        except KeyError:
 
569
            if section != DEFAULTSECT:
 
570
                raise NoSectionError(section)
 
571
        # Update with the entry specific variables
 
572
        if vars:
 
573
            for key, value in vars.items():
 
574
                d[self.optionxform(key)] = value
 
575
        options = list(d.keys())
 
576
        if "__name__" in options:
 
577
            options.remove("__name__")
 
578
        if raw:
 
579
            return [(option, d[option])
 
580
                    for option in options]
 
581
        else:
 
582
            return [(option, self._interpolate(section, option, d[option], d))
 
583
                    for option in options]
 
584
 
 
585
    def _interpolate(self, section, option, rawval, vars):
 
586
        # do the string interpolation
 
587
        value = rawval
 
588
        depth = MAX_INTERPOLATION_DEPTH
 
589
        while depth:                    # Loop through this until it's done
 
590
            depth -= 1
 
591
            if "%(" in value:
 
592
                value = self._KEYCRE.sub(self._interpolation_replace, value)
 
593
                try:
 
594
                    value = value % vars
 
595
                except KeyError as e:
 
596
                    raise InterpolationMissingOptionError(
 
597
                        option, section, rawval, e.args[0])
 
598
            else:
 
599
                break
 
600
        if "%(" in value:
 
601
            raise InterpolationDepthError(option, section, rawval)
 
602
        return value
 
603
 
 
604
    _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
 
605
 
 
606
    def _interpolation_replace(self, match):
 
607
        s = match.group(1)
 
608
        if s is None:
 
609
            return match.group()
 
610
        else:
 
611
            return "%%(%s)s" % self.optionxform(s)
 
612
 
 
613
 
 
614
class SafeConfigParser(ConfigParser):
 
615
 
 
616
    def _interpolate(self, section, option, rawval, vars):
 
617
        # do the string interpolation
 
618
        L = []
 
619
        self._interpolate_some(option, L, rawval, section, vars, 1)
 
620
        return ''.join(L)
 
621
 
 
622
    _interpvar_re = re.compile(r"%\(([^)]+)\)s")
 
623
    _badpercent_re = re.compile(r"%[^%]|%$")
 
624
 
 
625
    def _interpolate_some(self, option, accum, rest, section, map, depth):
 
626
        if depth > MAX_INTERPOLATION_DEPTH:
 
627
            raise InterpolationDepthError(option, section, rest)
 
628
        while rest:
 
629
            p = rest.find("%")
 
630
            if p < 0:
 
631
                accum.append(rest)
 
632
                return
 
633
            if p > 0:
 
634
                accum.append(rest[:p])
 
635
                rest = rest[p:]
 
636
            # p is no longer used
 
637
            c = rest[1:2]
 
638
            if c == "%":
 
639
                accum.append("%")
 
640
                rest = rest[2:]
 
641
            elif c == "(":
 
642
                m = self._interpvar_re.match(rest)
 
643
                if m is None:
 
644
                    raise InterpolationSyntaxError(option, section,
 
645
                        "bad interpolation variable reference %r" % rest)
 
646
                var = self.optionxform(m.group(1))
 
647
                rest = rest[m.end():]
 
648
                try:
 
649
                    v = map[var]
 
650
                except KeyError:
 
651
                    raise InterpolationMissingOptionError(
 
652
                        option, section, rest, var)
 
653
                if "%" in v:
 
654
                    self._interpolate_some(option, accum, v,
 
655
                                           section, map, depth + 1)
 
656
                else:
 
657
                    accum.append(v)
 
658
            else:
 
659
                raise InterpolationSyntaxError(
 
660
                    option, section,
 
661
                    "'%%' must be followed by '%%' or '(', found: %r" % (rest,))
 
662
 
 
663
    def set(self, section, option, value):
 
664
        """Set an option.  Extend ConfigParser.set: check for string values."""
 
665
        if not isinstance(value, str):
 
666
            raise TypeError("option values must be strings")
 
667
        # check for bad percent signs:
 
668
        # first, replace all "good" interpolations
 
669
        tmp_value = self._interpvar_re.sub('', value)
 
670
        # then, check if there's a lone percent sign left
 
671
        m = self._badpercent_re.search(tmp_value)
 
672
        if m:
 
673
            raise ValueError("invalid interpolation syntax in %r at "
 
674
                             "position %d" % (value, m.start()))
 
675
        ConfigParser.set(self, section, option, value)