raise InterpolationSyntaxError(
"More than one ':' found: %r" % (rest,))
except (KeyError, NoSectionError, NoOptionError):
raise InterpolationMissingOptionError(
option, section, rawval, ":".join(path)) from None
self._interpolate_some(parser, opt, accum, v, sect,
dict(parser.items(sect, raw=True)),
raise InterpolationSyntaxError(
"'$' must be followed by '$' or '{', "
class LegacyInterpolation(Interpolation):
"""Deprecated interpolation used in old versions of ConfigParser.
Use BasicInterpolation or ExtendedInterpolation instead."""
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
def before_get(self, parser, section, option, value, vars):
depth = MAX_INTERPOLATION_DEPTH
while depth: # Loop through this until it's done
if value and "%(" in value:
replace = functools.partial(self._interpolation_replace,
value = self._KEYCRE.sub(replace, value)
raise InterpolationMissingOptionError(
option, section, rawval, e.args[0]) from None
if value and "%(" in value:
raise InterpolationDepthError(option, section, rawval)
def before_set(self, parser, section, option, value):
def _interpolation_replace(match, parser):
return "%%(%s)s" % parser.optionxform(s)
class RawConfigParser(MutableMapping):
"""ConfigParser that does not do interpolation."""
# Regular expressions for parsing section headers and options
(?P<header>[^]]+) # very permissive!
(?P<option>.*?) # very permissive!
\s*(?P<vi>{delim})\s* # any number of space/tab,
# followed by any space/tab
(?P<value>.*)$ # everything up to eol
(?P<option>.*?) # very permissive!
\s*(?: # any number of space/tab,
(?P<vi>{delim})\s* # optionally followed by
# delimiters, followed by any
(?P<value>.*))?$ # everything up to eol
# Interpolation algorithm to be used if the user does not specify another
_DEFAULT_INTERPOLATION = Interpolation()
# Compiled regular expression for matching sections
SECTCRE = re.compile(_SECT_TMPL, re.VERBOSE)
# Compiled regular expression for matching options with typical separators
OPTCRE = re.compile(_OPT_TMPL.format(delim="=|:"), re.VERBOSE)
# Compiled regular expression for matching options with optional values
# delimited using typical separators
OPTCRE_NV = re.compile(_OPT_NV_TMPL.format(delim="=|:"), re.VERBOSE)
# Compiled regular expression for matching leading whitespace in a line
NONSPACECRE = re.compile(r"\S")
# Possible boolean values in the configuration.
BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True,
'0': False, 'no': False, 'false': False, 'off': False}
def __init__(self, defaults=None, dict_type=_default_dict,
allow_no_value=False, *, delimiters=('=', ':'),
comment_prefixes=('#', ';'), inline_comment_prefixes=None,
strict=True, empty_lines_in_values=True,
default_section=DEFAULTSECT,
interpolation=_UNSET, converters=_UNSET):
self._sections = self._dict()
self._defaults = self._dict()
self._converters = ConverterMapping(self)
self._proxies = self._dict()
self._proxies[default_section] = SectionProxy(self, default_section)
for key, value in defaults.items():
self._defaults[self.optionxform(key)] = value
self._delimiters = tuple(delimiters)
if delimiters == ('=', ':'):
self._optcre = self.OPTCRE_NV if allow_no_value else self.OPTCRE
d = "|".join(re.escape(d) for d in delimiters)
self._optcre = re.compile(self._OPT_NV_TMPL.format(delim=d),
self._optcre = re.compile(self._OPT_TMPL.format(delim=d),
self._comment_prefixes = tuple(comment_prefixes or ())
self._inline_comment_prefixes = tuple(inline_comment_prefixes or ())
self._allow_no_value = allow_no_value
self._empty_lines_in_values = empty_lines_in_values
self.default_section=default_section
self._interpolation = interpolation
if self._interpolation is _UNSET:
self._interpolation = self._DEFAULT_INTERPOLATION
if self._interpolation is None:
self._interpolation = Interpolation()
if converters is not _UNSET:
self._converters.update(converters)
"""Return a list of section names, excluding [DEFAULT]"""
# self._sections will never have [DEFAULT] in it
return list(self._sections.keys())
def add_section(self, section):
"""Create a new section in the configuration.
Raise DuplicateSectionError if a section by the specified name
already exists. Raise ValueError if name is DEFAULT.
if section == self.default_section:
raise ValueError('Invalid section name: %r' % section)
if section in self._sections:
raise DuplicateSectionError(section)
self._sections[section] = self._dict()
self._proxies[section] = SectionProxy(self, section)
def has_section(self, section):
"""Indicate whether the named section is present in the configuration.
The DEFAULT section is not acknowledged.
return section in self._sections
def options(self, section):
"""Return a list of option names for the given section name."""
opts = self._sections[section].copy()
raise NoSectionError(section) from None
opts.update(self._defaults)
def read(self, filenames, encoding=None):
"""Read and parse a filename or an iterable of filenames.
Files that cannot be opened are silently ignored; this is
designed so that you can specify an iterable of potential
configuration file locations (e.g. current directory, user's
home directory, systemwide directory), and all existing
configuration files in the iterable will be read. A single
filename may also be given.
Return list of successfully read files.
if isinstance(filenames, (str, os.PathLike)):
for filename in filenames:
with open(filename, encoding=encoding) as fp:
if isinstance(filename, os.PathLike):
filename = os.fspath(filename)
def read_file(self, f, source=None):
"""Like read() but the argument must be a file-like object.
The `f' argument must be iterable, returning one line at a time.
Optional second argument is the `source' specifying the name of the
file being read. If not given, it is taken from f.name. If `f' has no
`name' attribute, `<???>' is used.
def read_string(self, string, source='<string>'):
"""Read configuration from a given string."""
sfile = io.StringIO(string)
self.read_file(sfile, source)
def read_dict(self, dictionary, source='<dict>'):
"""Read configuration from a dictionary.
Keys are section names, values are dictionaries with keys and values
that should be present in the section. If the used dictionary type
preserves order, sections and their keys will be added in order.
All types held in the dictionary are converted to strings during
reading, including section names, option names and keys.
Optional second argument is the `source' specifying the name of the
for section, keys in dictionary.items():
self.add_section(section)
except (DuplicateSectionError, ValueError):
if self._strict and section in elements_added:
elements_added.add(section)
for key, value in keys.items():
key = self.optionxform(str(key))
if self._strict and (section, key) in elements_added:
raise DuplicateOptionError(section, key, source)
elements_added.add((section, key))
self.set(section, key, value)
def readfp(self, fp, filename=None):
"""Deprecated, use read_file instead."""
"This method will be removed in future versions. "
"Use 'parser.read_file()' instead.",
DeprecationWarning, stacklevel=2
self.read_file(fp, source=filename)
def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
"""Get an option value for a given section.
If `vars' is provided, it must be a dictionary. The option is looked up
in `vars' (if provided), `section', and in `DEFAULTSECT' in that order.
If the key is not found and `fallback' is provided, it is used as
a fallback value. `None' can be provided as a `fallback' value.
If interpolation is enabled and the optional argument `raw' is False,
all interpolations are expanded in the return values.
Arguments `raw', `vars', and `fallback' are keyword only.
The section DEFAULT is special.
d = self._unify_values(section, vars)
option = self.optionxform(option)
raise NoOptionError(option, section)
return self._interpolation.before_get(self, section, option, value,
def _get(self, section, conv, option, **kwargs):
return conv(self.get(section, option, **kwargs))
def _get_conv(self, section, option, conv, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self._get(section, conv, option, raw=raw, vars=vars,
except (NoSectionError, NoOptionError):
# getint, getfloat and getboolean provided directly for backwards compat
def getint(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self._get_conv(section, option, int, raw=raw, vars=vars,
fallback=fallback, **kwargs)
def getfloat(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self._get_conv(section, option, float, raw=raw, vars=vars,
fallback=fallback, **kwargs)
def getboolean(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self._get_conv(section, option, self._convert_to_boolean,
raw=raw, vars=vars, fallback=fallback, **kwargs)
def items(self, section=_UNSET, raw=False, vars=None):
"""Return a list of (name, value) tuples for each option in a section.
All % interpolations are expanded in the return values, based on the
defaults passed into the constructor, unless the optional argument
`raw' is true. Additional substitutions may be provided using the
`vars' argument, which must be a dictionary whose contents overrides
any pre-existing defaults.
The section DEFAULT is special.
d = self._defaults.copy()
d.update(self._sections[section])
if section != self.default_section:
raise NoSectionError(section)
# Update with the entry specific variables
for key, value in vars.items():
d[self.optionxform(key)] = value
value_getter = lambda option: self._interpolation.before_get(self,
section, option, d[option], d)
value_getter = lambda option: d[option]
return [(option, value_getter(option)) for option in d.keys()]
"""Remove a section from the parser and return it as
a (section_name, section_proxy) tuple. If no section is present, raise
The section DEFAULT is never returned because it cannot be removed.
for key in self.sections():
def optionxform(self, optionstr):
def has_option(self, section, option):
"""Check for the existence of a given option in a given section.
If the specified `section' is None or an empty string, DEFAULT is
assumed. If the specified `section' does not exist, returns False."""
if not section or section == self.default_section:
option = self.optionxform(option)
return option in self._defaults
elif section not in self._sections:
option = self.optionxform(option)
return (option in self._sections[section]
or option in self._defaults)
def set(self, section, option, value=None):
value = self._interpolation.before_set(self, section, option,
if not section or section == self.default_section:
sectdict = self._defaults
sectdict = self._sections[section]
raise NoSectionError(section) from None
sectdict[self.optionxform(option)] = value
def write(self, fp, space_around_delimiters=True):
"""Write an .ini-format representation of the configuration state.
If `space_around_delimiters' is True (the default), delimiters
between keys and values are surrounded by spaces.
if space_around_delimiters:
d = " {} ".format(self._delimiters[0])
self._write_section(fp, self.default_section,
self._defaults.items(), d)
for section in self._sections:
self._write_section(fp, section,
self._sections[section].items(), d)
def _write_section(self, fp, section_name, section_items, delimiter):
"""Write a single section to the specified `fp'."""
fp.write("[{}]\n".format(section_name))
for key, value in section_items:
value = self._interpolation.before_write(self, section_name, key,
if value is not None or not self._allow_no_value:
value = delimiter + str(value).replace('\n', '\n\t')
fp.write("{}{}\n".format(key, value))
def remove_option(self, section, option):
if not section or section == self.default_section:
sectdict = self._defaults
sectdict = self._sections[section]
raise NoSectionError(section) from None
option = self.optionxform(option)
existed = option in sectdict
def remove_section(self, section):
"""Remove a file section."""
existed = section in self._sections
del self._sections[section]
del self._proxies[section]
def __getitem__(self, key):
if key != self.default_section and not self.has_section(key):
return self._proxies[key]
def __setitem__(self, key, value):
# To conform with the mapping protocol, overwrites existing values in
# XXX this is not atomic if read_dict fails at any point. Then again,
# no update method in configparser is atomic in this implementation.
if key == self.default_section:
elif key in self._sections:
self._sections[key].clear()
self.read_dict({key: value})
def __delitem__(self, key):
if key == self.default_section:
raise ValueError("Cannot remove the default section.")
if not self.has_section(key):
def __contains__(self, key):
return key == self.default_section or self.has_section(key)
return len(self._sections) + 1 # the default section
# XXX does it break when underlying container state changed?
return itertools.chain((self.default_section,), self._sections.keys())
def _read(self, fp, fpname):
"""Parse a sectioned configuration file.
Each section in a configuration file contains a header, indicated by
a name in square brackets (`[]'), plus key/value options, indicated by
`name' and `value' delimited with a specific substring (`=' or `:' by
Values can span multiple lines, as long as they are indented deeper
than the first line of the value. Depending on the parser's mode, blank