~pythonregexp2.7/python/issue2636-22

« back to all changes in this revision

Viewing changes to Lib/configparser.py

  • Committer: Jeffrey C. "The TimeHorse" Jacobs
  • Date: 2008-06-09 14:36:32 UTC
  • mfrom: (39021.1.402 Regexp-2.6)
  • Revision ID: darklord@timehorse.com-20080609143632-wwwkx92u1t5l7yd3
Merged in changes from the latest python source snapshot.

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