1
"""Configuration file parser.
3
A setup file consists of sections, lead by a "[section]" header,
4
and followed by "name: value" entries, with continuations and such in
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.
12
something: %(dir)s/whatever
14
would resolve the "%(dir)s" to the value of dir. All reference
15
expansions are done late, on demand.
17
Intrinsic defaults can be specified by passing them into the
18
ConfigParser constructor as a dictionary.
22
ConfigParser -- responsible for parsing a list of
23
configuration files, and managing the parsed database.
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.
34
return all the configuration section names, sans DEFAULT
37
return whether the given section exists
39
has_option(section, option)
40
return whether the given option exists in the given section
43
return list of configuration options for the named section
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.
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).
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.
62
getint(section, options)
63
like get(), but convert value to an integer
65
getfloat(section, options)
66
like get(), but convert value to a float
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.
73
items(section, raw=False, vars=None)
74
return a list of tuples with (name, value) for each option
77
remove_section(section)
78
remove the given file section and all its options
80
remove_option(section, option)
81
remove the given option from the given section
83
set(section, option, value)
87
write the configuration state in .ini format
91
from collections import OrderedDict as _default_dict
93
# fallback for setup.py which hasn't yet built _collections
98
__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError",
99
"InterpolationError", "InterpolationDepthError",
100
"InterpolationSyntaxError", "ParsingError",
101
"MissingSectionHeaderError",
102
"ConfigParser", "SafeConfigParser", "RawConfigParser",
103
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
105
DEFAULTSECT = "DEFAULT"
107
MAX_INTERPOLATION_DEPTH = 10
112
class Error(Exception):
113
"""Base class for ConfigParser exceptions."""
115
def _get_message(self):
116
"""Getter for 'message'; needed only to override deprecation in
118
return self.__message
120
def _set_message(self, value):
121
"""Setter for 'message'; needed only to override deprecation in
123
self.__message = value
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)
130
def __init__(self, msg=''):
132
Exception.__init__(self, msg)
139
class NoSectionError(Error):
140
"""Raised when no section matches a requested option."""
142
def __init__(self, section):
143
Error.__init__(self, 'No section: %r' % (section,))
144
self.section = section
146
class DuplicateSectionError(Error):
147
"""Raised when a section is multiply-created."""
149
def __init__(self, section):
150
Error.__init__(self, "Section %r already exists" % section)
151
self.section = section
153
class NoOptionError(Error):
154
"""A requested option was not found."""
156
def __init__(self, option, section):
157
Error.__init__(self, "No option %r in section: %r" %
160
self.section = section
162
class InterpolationError(Error):
163
"""Base class for interpolation-related exceptions."""
165
def __init__(self, option, section, msg):
166
Error.__init__(self, msg)
168
self.section = section
170
class InterpolationMissingOptionError(InterpolationError):
171
"""A string substitution required a setting which was not available."""
173
def __init__(self, option, section, rawval, reference):
174
msg = ("Bad value substitution:\n"
179
% (section, option, reference, rawval))
180
InterpolationError.__init__(self, option, section, msg)
181
self.reference = reference
183
class InterpolationSyntaxError(InterpolationError):
184
"""Raised when the source text into which substitutions are made
185
does not conform to the required syntax."""
187
class InterpolationDepthError(InterpolationError):
188
"""Raised when substitutions are nested too deeply."""
190
def __init__(self, option, section, rawval):
191
msg = ("Value interpolation too deeply recursive:\n"
195
% (section, option, rawval))
196
InterpolationError.__init__(self, option, section, msg)
198
class ParsingError(Error):
199
"""Raised when a configuration file does not follow legal syntax."""
201
def __init__(self, filename):
202
Error.__init__(self, 'File contains parsing errors: %s' % filename)
203
self.filename = filename
206
def append(self, lineno, line):
207
self.errors.append((lineno, line))
208
self.message += '\n\t[line %2d]: %s' % (lineno, line)
210
class MissingSectionHeaderError(ParsingError):
211
"""Raised when a key-value pair is found before any section header."""
213
def __init__(self, filename, lineno, line):
216
'File contains no section headers.\nfile: %s, line: %d\n%r' %
217
(filename, lineno, line))
218
self.filename = filename
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()
229
for key, value in defaults.items():
230
self._defaults[self.optionxform(key)] = value
233
return self._defaults
236
"""Return a list of section names, excluding [DEFAULT]"""
237
# self._sections will never have [DEFAULT] in it
238
return list(self._sections.keys())
240
def add_section(self, section):
241
"""Create a new section in the configuration.
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.
247
if section.lower() == "default":
248
raise ValueError('Invalid section name: %s' % section)
250
if section in self._sections:
251
raise DuplicateSectionError(section)
252
self._sections[section] = self._dict()
254
def has_section(self, section):
255
"""Indicate whether the named section is present in the configuration.
257
The DEFAULT section is not acknowledged.
259
return section in self._sections
261
def options(self, section):
262
"""Return a list of option names for the given section name."""
264
opts = self._sections[section].copy()
266
raise NoSectionError(section)
267
opts.update(self._defaults)
268
if '__name__' in opts:
270
return list(opts.keys())
272
def read(self, filenames):
273
"""Read and parse a filename or a list of filenames.
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.
282
Return list of successfully read files.
284
if isinstance(filenames, str):
285
filenames = [filenames]
287
for filename in filenames:
292
self._read(fp, filename)
294
read_ok.append(filename)
297
def readfp(self, fp, filename=None):
298
"""Like read() but the argument must be a file-like object.
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
309
except AttributeError:
311
self._read(fp, filename)
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]
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]
327
raise NoOptionError(option, section)
329
def items(self, section):
331
d2 = self._sections[section]
333
if section != DEFAULTSECT:
334
raise NoSectionError(section)
336
d = self._defaults.copy()
342
def _get(self, section, conv, option):
343
return conv(self.get(section, option))
345
def getint(self, section, option):
346
return self._get(section, int, option)
348
def getfloat(self, section, option):
349
return self._get(section, float, option)
351
_boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
352
'0': False, 'no': False, 'false': False, 'off': False}
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()]
360
def optionxform(self, optionstr):
361
return optionstr.lower()
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:
371
option = self.optionxform(option)
372
return (option in self._sections[section]
373
or option in self._defaults)
375
def set(self, section, option, value):
377
if not section or section == DEFAULTSECT:
378
sectdict = self._defaults
381
sectdict = self._sections[section]
383
raise NoSectionError(section)
384
sectdict[self.optionxform(option)] = value
387
"""Write an .ini-format representation of the configuration state."""
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')))
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')))
401
def remove_option(self, section, option):
402
"""Remove an option."""
403
if not section or section == DEFAULTSECT:
404
sectdict = self._defaults
407
sectdict = self._sections[section]
409
raise NoSectionError(section)
410
option = self.optionxform(option)
411
existed = option in sectdict
416
def remove_section(self, section):
417
"""Remove a file section."""
418
existed = section in self._sections
420
del self._sections[section]
424
# Regular expressions for parsing section headers and options.
426
SECTCRE = re.compile(
428
r'(?P<header>[^]]+)' # very permissive!
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
437
r'(?P<value>.*)$' # everything up to eol
440
def _read(self, fp, fpname):
441
"""Parse a sectioned setup file.
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.
450
cursect = None # None, or a dictionary
453
e = None # None, or an exception
459
# comment or blank line?
460
if line.strip() == '' or line[0] in '#;':
462
if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
463
# no leading whitespace
466
if line[0].isspace() and cursect is not None and optname:
469
cursect[optname] = "%s\n%s" % (cursect[optname], value)
470
# a section header or option header?
472
# is it a section header?
473
mo = self.SECTCRE.match(line)
475
sectname = mo.group('header')
476
if sectname in self._sections:
477
cursect = self._sections[sectname]
478
elif sectname == DEFAULTSECT:
479
cursect = self._defaults
481
cursect = self._dict()
482
cursect['__name__'] = sectname
483
self._sections[sectname] = cursect
484
# So sections can't start with a continuation line
486
# no section header in the file?
487
elif cursect is None:
488
raise MissingSectionHeaderError(fpname, lineno, line)
491
mo = self.OPTCRE.match(line)
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()
504
optname = self.optionxform(optname.rstrip())
505
cursect[optname] = optval
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
512
e = ParsingError(fpname)
513
e.append(lineno, repr(line))
514
# if any parsing errors occurred, raise an exception
519
class ConfigParser(RawConfigParser):
521
def get(self, section, option, raw=False, vars=None):
522
"""Get an option value for a given section.
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.
530
The section DEFAULT is special.
532
d = self._defaults.copy()
534
d.update(self._sections[section])
536
if section != DEFAULTSECT:
537
raise NoSectionError(section)
538
# Update with the entry specific variables
540
for key, value in vars.items():
541
d[self.optionxform(key)] = value
542
option = self.optionxform(option)
546
raise NoOptionError(option, section)
551
return self._interpolate(section, option, value, d)
553
def items(self, section, raw=False, vars=None):
554
"""Return a list of tuples with (name, value) for each option
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.
563
The section DEFAULT is special.
565
d = self._defaults.copy()
567
d.update(self._sections[section])
569
if section != DEFAULTSECT:
570
raise NoSectionError(section)
571
# Update with the entry specific variables
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__")
579
return [(option, d[option])
580
for option in options]
582
return [(option, self._interpolate(section, option, d[option], d))
583
for option in options]
585
def _interpolate(self, section, option, rawval, vars):
586
# do the string interpolation
588
depth = MAX_INTERPOLATION_DEPTH
589
while depth: # Loop through this until it's done
592
value = self._KEYCRE.sub(self._interpolation_replace, value)
595
except KeyError as e:
596
raise InterpolationMissingOptionError(
597
option, section, rawval, e.args[0])
601
raise InterpolationDepthError(option, section, rawval)
604
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
606
def _interpolation_replace(self, match):
611
return "%%(%s)s" % self.optionxform(s)
614
class SafeConfigParser(ConfigParser):
616
def _interpolate(self, section, option, rawval, vars):
617
# do the string interpolation
619
self._interpolate_some(option, L, rawval, section, vars, 1)
622
_interpvar_re = re.compile(r"%\(([^)]+)\)s")
623
_badpercent_re = re.compile(r"%[^%]|%$")
625
def _interpolate_some(self, option, accum, rest, section, map, depth):
626
if depth > MAX_INTERPOLATION_DEPTH:
627
raise InterpolationDepthError(option, section, rest)
634
accum.append(rest[:p])
636
# p is no longer used
642
m = self._interpvar_re.match(rest)
644
raise InterpolationSyntaxError(option, section,
645
"bad interpolation variable reference %r" % rest)
646
var = self.optionxform(m.group(1))
647
rest = rest[m.end():]
651
raise InterpolationMissingOptionError(
652
option, section, rest, var)
654
self._interpolate_some(option, accum, v,
655
section, map, depth + 1)
659
raise InterpolationSyntaxError(
661
"'%%' must be followed by '%%' or '(', found: %r" % (rest,))
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)
673
raise ValueError("invalid interpolation syntax in %r at "
674
"position %d" % (value, m.start()))
675
ConfigParser.set(self, section, option, value)