(root)/
Python-3.12.0/
Lib/
configparser.py
       1  """Configuration file parser.
       2  
       3  A configuration 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  Intrinsic defaults can be specified by passing them into the
       8  ConfigParser constructor as a dictionary.
       9  
      10  class:
      11  
      12  ConfigParser -- responsible for parsing a list of
      13                      configuration files, and managing the parsed database.
      14  
      15      methods:
      16  
      17      __init__(defaults=None, dict_type=_default_dict, allow_no_value=False,
      18               delimiters=('=', ':'), comment_prefixes=('#', ';'),
      19               inline_comment_prefixes=None, strict=True,
      20               empty_lines_in_values=True, default_section='DEFAULT',
      21               interpolation=<unset>, converters=<unset>):
      22  
      23          Create the parser. When `defaults` is given, it is initialized into the
      24          dictionary or intrinsic defaults. The keys must be strings, the values
      25          must be appropriate for %()s string interpolation.
      26  
      27          When `dict_type` is given, it will be used to create the dictionary
      28          objects for the list of sections, for the options within a section, and
      29          for the default values.
      30  
      31          When `delimiters` is given, it will be used as the set of substrings
      32          that divide keys from values.
      33  
      34          When `comment_prefixes` is given, it will be used as the set of
      35          substrings that prefix comments in empty lines. Comments can be
      36          indented.
      37  
      38          When `inline_comment_prefixes` is given, it will be used as the set of
      39          substrings that prefix comments in non-empty lines.
      40  
      41          When `strict` is True, the parser won't allow for any section or option
      42          duplicates while reading from a single source (file, string or
      43          dictionary). Default is True.
      44  
      45          When `empty_lines_in_values` is False (default: True), each empty line
      46          marks the end of an option. Otherwise, internal empty lines of
      47          a multiline option are kept as part of the value.
      48  
      49          When `allow_no_value` is True (default: False), options without
      50          values are accepted; the value presented for these is None.
      51  
      52          When `default_section` is given, the name of the special section is
      53          named accordingly. By default it is called ``"DEFAULT"`` but this can
      54          be customized to point to any other valid section name. Its current
      55          value can be retrieved using the ``parser_instance.default_section``
      56          attribute and may be modified at runtime.
      57  
      58          When `interpolation` is given, it should be an Interpolation subclass
      59          instance. It will be used as the handler for option value
      60          pre-processing when using getters. RawConfigParser objects don't do
      61          any sort of interpolation, whereas ConfigParser uses an instance of
      62          BasicInterpolation. The library also provides a ``zc.buildout``
      63          inspired ExtendedInterpolation implementation.
      64  
      65          When `converters` is given, it should be a dictionary where each key
      66          represents the name of a type converter and each value is a callable
      67          implementing the conversion from string to the desired datatype. Every
      68          converter gets its corresponding get*() method on the parser object and
      69          section proxies.
      70  
      71      sections()
      72          Return all the configuration section names, sans DEFAULT.
      73  
      74      has_section(section)
      75          Return whether the given section exists.
      76  
      77      has_option(section, option)
      78          Return whether the given option exists in the given section.
      79  
      80      options(section)
      81          Return list of configuration options for the named section.
      82  
      83      read(filenames, encoding=None)
      84          Read and parse the iterable of named configuration files, given by
      85          name.  A single filename is also allowed.  Non-existing files
      86          are ignored.  Return list of successfully read files.
      87  
      88      read_file(f, filename=None)
      89          Read and parse one configuration file, given as a file object.
      90          The filename defaults to f.name; it is only used in error
      91          messages (if f has no `name` attribute, the string `<???>` is used).
      92  
      93      read_string(string)
      94          Read configuration from a given string.
      95  
      96      read_dict(dictionary)
      97          Read configuration from a dictionary. Keys are section names,
      98          values are dictionaries with keys and values that should be present
      99          in the section. If the used dictionary type preserves order, sections
     100          and their keys will be added in order. Values are automatically
     101          converted to strings.
     102  
     103      get(section, option, raw=False, vars=None, fallback=_UNSET)
     104          Return a string value for the named option.  All % interpolations are
     105          expanded in the return values, based on the defaults passed into the
     106          constructor and the DEFAULT section.  Additional substitutions may be
     107          provided using the `vars` argument, which must be a dictionary whose
     108          contents override any pre-existing defaults. If `option` is a key in
     109          `vars`, the value from `vars` is used.
     110  
     111      getint(section, options, raw=False, vars=None, fallback=_UNSET)
     112          Like get(), but convert value to an integer.
     113  
     114      getfloat(section, options, raw=False, vars=None, fallback=_UNSET)
     115          Like get(), but convert value to a float.
     116  
     117      getboolean(section, options, raw=False, vars=None, fallback=_UNSET)
     118          Like get(), but convert value to a boolean (currently case
     119          insensitively defined as 0, false, no, off for False, and 1, true,
     120          yes, on for True).  Returns False or True.
     121  
     122      items(section=_UNSET, raw=False, vars=None)
     123          If section is given, return a list of tuples with (name, value) for
     124          each option in the section. Otherwise, return a list of tuples with
     125          (section_name, section_proxy) for each section, including DEFAULTSECT.
     126  
     127      remove_section(section)
     128          Remove the given file section and all its options.
     129  
     130      remove_option(section, option)
     131          Remove the given option from the given section.
     132  
     133      set(section, option, value)
     134          Set the given option.
     135  
     136      write(fp, space_around_delimiters=True)
     137          Write the configuration state in .ini format. If
     138          `space_around_delimiters` is True (the default), delimiters
     139          between keys and values are surrounded by spaces.
     140  """
     141  
     142  from collections.abc import MutableMapping
     143  from collections import ChainMap as _ChainMap
     144  import functools
     145  import io
     146  import itertools
     147  import os
     148  import re
     149  import sys
     150  import warnings
     151  
     152  __all__ = ("NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
     153             "NoOptionError", "InterpolationError", "InterpolationDepthError",
     154             "InterpolationMissingOptionError", "InterpolationSyntaxError",
     155             "ParsingError", "MissingSectionHeaderError",
     156             "ConfigParser", "RawConfigParser",
     157             "Interpolation", "BasicInterpolation",  "ExtendedInterpolation",
     158             "LegacyInterpolation", "SectionProxy", "ConverterMapping",
     159             "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH")
     160  
     161  _default_dict = dict
     162  DEFAULTSECT = "DEFAULT"
     163  
     164  MAX_INTERPOLATION_DEPTH = 10
     165  
     166  
     167  
     168  # exception classes
     169  class ESC[4;38;5;81mError(ESC[4;38;5;149mException):
     170      """Base class for ConfigParser exceptions."""
     171  
     172      def __init__(self, msg=''):
     173          self.message = msg
     174          Exception.__init__(self, msg)
     175  
     176      def __repr__(self):
     177          return self.message
     178  
     179      __str__ = __repr__
     180  
     181  
     182  class ESC[4;38;5;81mNoSectionError(ESC[4;38;5;149mError):
     183      """Raised when no section matches a requested option."""
     184  
     185      def __init__(self, section):
     186          Error.__init__(self, 'No section: %r' % (section,))
     187          self.section = section
     188          self.args = (section, )
     189  
     190  
     191  class ESC[4;38;5;81mDuplicateSectionError(ESC[4;38;5;149mError):
     192      """Raised when a section is repeated in an input source.
     193  
     194      Possible repetitions that raise this exception are: multiple creation
     195      using the API or in strict parsers when a section is found more than once
     196      in a single input file, string or dictionary.
     197      """
     198  
     199      def __init__(self, section, source=None, lineno=None):
     200          msg = [repr(section), " already exists"]
     201          if source is not None:
     202              message = ["While reading from ", repr(source)]
     203              if lineno is not None:
     204                  message.append(" [line {0:2d}]".format(lineno))
     205              message.append(": section ")
     206              message.extend(msg)
     207              msg = message
     208          else:
     209              msg.insert(0, "Section ")
     210          Error.__init__(self, "".join(msg))
     211          self.section = section
     212          self.source = source
     213          self.lineno = lineno
     214          self.args = (section, source, lineno)
     215  
     216  
     217  class ESC[4;38;5;81mDuplicateOptionError(ESC[4;38;5;149mError):
     218      """Raised by strict parsers when an option is repeated in an input source.
     219  
     220      Current implementation raises this exception only when an option is found
     221      more than once in a single file, string or dictionary.
     222      """
     223  
     224      def __init__(self, section, option, source=None, lineno=None):
     225          msg = [repr(option), " in section ", repr(section),
     226                 " already exists"]
     227          if source is not None:
     228              message = ["While reading from ", repr(source)]
     229              if lineno is not None:
     230                  message.append(" [line {0:2d}]".format(lineno))
     231              message.append(": option ")
     232              message.extend(msg)
     233              msg = message
     234          else:
     235              msg.insert(0, "Option ")
     236          Error.__init__(self, "".join(msg))
     237          self.section = section
     238          self.option = option
     239          self.source = source
     240          self.lineno = lineno
     241          self.args = (section, option, source, lineno)
     242  
     243  
     244  class ESC[4;38;5;81mNoOptionError(ESC[4;38;5;149mError):
     245      """A requested option was not found."""
     246  
     247      def __init__(self, option, section):
     248          Error.__init__(self, "No option %r in section: %r" %
     249                         (option, section))
     250          self.option = option
     251          self.section = section
     252          self.args = (option, section)
     253  
     254  
     255  class ESC[4;38;5;81mInterpolationError(ESC[4;38;5;149mError):
     256      """Base class for interpolation-related exceptions."""
     257  
     258      def __init__(self, option, section, msg):
     259          Error.__init__(self, msg)
     260          self.option = option
     261          self.section = section
     262          self.args = (option, section, msg)
     263  
     264  
     265  class ESC[4;38;5;81mInterpolationMissingOptionError(ESC[4;38;5;149mInterpolationError):
     266      """A string substitution required a setting which was not available."""
     267  
     268      def __init__(self, option, section, rawval, reference):
     269          msg = ("Bad value substitution: option {!r} in section {!r} contains "
     270                 "an interpolation key {!r} which is not a valid option name. "
     271                 "Raw value: {!r}".format(option, section, reference, rawval))
     272          InterpolationError.__init__(self, option, section, msg)
     273          self.reference = reference
     274          self.args = (option, section, rawval, reference)
     275  
     276  
     277  class ESC[4;38;5;81mInterpolationSyntaxError(ESC[4;38;5;149mInterpolationError):
     278      """Raised when the source text contains invalid syntax.
     279  
     280      Current implementation raises this exception when the source text into
     281      which substitutions are made does not conform to the required syntax.
     282      """
     283  
     284  
     285  class ESC[4;38;5;81mInterpolationDepthError(ESC[4;38;5;149mInterpolationError):
     286      """Raised when substitutions are nested too deeply."""
     287  
     288      def __init__(self, option, section, rawval):
     289          msg = ("Recursion limit exceeded in value substitution: option {!r} "
     290                 "in section {!r} contains an interpolation key which "
     291                 "cannot be substituted in {} steps. Raw value: {!r}"
     292                 "".format(option, section, MAX_INTERPOLATION_DEPTH,
     293                           rawval))
     294          InterpolationError.__init__(self, option, section, msg)
     295          self.args = (option, section, rawval)
     296  
     297  
     298  class ESC[4;38;5;81mParsingError(ESC[4;38;5;149mError):
     299      """Raised when a configuration file does not follow legal syntax."""
     300  
     301      def __init__(self, source):
     302          super().__init__(f'Source contains parsing errors: {source!r}')
     303          self.source = source
     304          self.errors = []
     305          self.args = (source, )
     306  
     307      def append(self, lineno, line):
     308          self.errors.append((lineno, line))
     309          self.message += '\n\t[line %2d]: %s' % (lineno, line)
     310  
     311  
     312  class ESC[4;38;5;81mMissingSectionHeaderError(ESC[4;38;5;149mParsingError):
     313      """Raised when a key-value pair is found before any section header."""
     314  
     315      def __init__(self, filename, lineno, line):
     316          Error.__init__(
     317              self,
     318              'File contains no section headers.\nfile: %r, line: %d\n%r' %
     319              (filename, lineno, line))
     320          self.source = filename
     321          self.lineno = lineno
     322          self.line = line
     323          self.args = (filename, lineno, line)
     324  
     325  
     326  # Used in parser getters to indicate the default behaviour when a specific
     327  # option is not found it to raise an exception. Created to enable `None` as
     328  # a valid fallback value.
     329  _UNSET = object()
     330  
     331  
     332  class ESC[4;38;5;81mInterpolation:
     333      """Dummy interpolation that passes the value through with no changes."""
     334  
     335      def before_get(self, parser, section, option, value, defaults):
     336          return value
     337  
     338      def before_set(self, parser, section, option, value):
     339          return value
     340  
     341      def before_read(self, parser, section, option, value):
     342          return value
     343  
     344      def before_write(self, parser, section, option, value):
     345          return value
     346  
     347  
     348  class ESC[4;38;5;81mBasicInterpolation(ESC[4;38;5;149mInterpolation):
     349      """Interpolation as implemented in the classic ConfigParser.
     350  
     351      The option values can contain format strings which refer to other values in
     352      the same section, or values in the special default section.
     353  
     354      For example:
     355  
     356          something: %(dir)s/whatever
     357  
     358      would resolve the "%(dir)s" to the value of dir.  All reference
     359      expansions are done late, on demand. If a user needs to use a bare % in
     360      a configuration file, she can escape it by writing %%. Other % usage
     361      is considered a user error and raises `InterpolationSyntaxError`."""
     362  
     363      _KEYCRE = re.compile(r"%\(([^)]+)\)s")
     364  
     365      def before_get(self, parser, section, option, value, defaults):
     366          L = []
     367          self._interpolate_some(parser, option, L, value, section, defaults, 1)
     368          return ''.join(L)
     369  
     370      def before_set(self, parser, section, option, value):
     371          tmp_value = value.replace('%%', '') # escaped percent signs
     372          tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax
     373          if '%' in tmp_value:
     374              raise ValueError("invalid interpolation syntax in %r at "
     375                               "position %d" % (value, tmp_value.find('%')))
     376          return value
     377  
     378      def _interpolate_some(self, parser, option, accum, rest, section, map,
     379                            depth):
     380          rawval = parser.get(section, option, raw=True, fallback=rest)
     381          if depth > MAX_INTERPOLATION_DEPTH:
     382              raise InterpolationDepthError(option, section, rawval)
     383          while rest:
     384              p = rest.find("%")
     385              if p < 0:
     386                  accum.append(rest)
     387                  return
     388              if p > 0:
     389                  accum.append(rest[:p])
     390                  rest = rest[p:]
     391              # p is no longer used
     392              c = rest[1:2]
     393              if c == "%":
     394                  accum.append("%")
     395                  rest = rest[2:]
     396              elif c == "(":
     397                  m = self._KEYCRE.match(rest)
     398                  if m is None:
     399                      raise InterpolationSyntaxError(option, section,
     400                          "bad interpolation variable reference %r" % rest)
     401                  var = parser.optionxform(m.group(1))
     402                  rest = rest[m.end():]
     403                  try:
     404                      v = map[var]
     405                  except KeyError:
     406                      raise InterpolationMissingOptionError(
     407                          option, section, rawval, var) from None
     408                  if "%" in v:
     409                      self._interpolate_some(parser, option, accum, v,
     410                                             section, map, depth + 1)
     411                  else:
     412                      accum.append(v)
     413              else:
     414                  raise InterpolationSyntaxError(
     415                      option, section,
     416                      "'%%' must be followed by '%%' or '(', "
     417                      "found: %r" % (rest,))
     418  
     419  
     420  class ESC[4;38;5;81mExtendedInterpolation(ESC[4;38;5;149mInterpolation):
     421      """Advanced variant of interpolation, supports the syntax used by
     422      `zc.buildout`. Enables interpolation between sections."""
     423  
     424      _KEYCRE = re.compile(r"\$\{([^}]+)\}")
     425  
     426      def before_get(self, parser, section, option, value, defaults):
     427          L = []
     428          self._interpolate_some(parser, option, L, value, section, defaults, 1)
     429          return ''.join(L)
     430  
     431      def before_set(self, parser, section, option, value):
     432          tmp_value = value.replace('$$', '') # escaped dollar signs
     433          tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax
     434          if '$' in tmp_value:
     435              raise ValueError("invalid interpolation syntax in %r at "
     436                               "position %d" % (value, tmp_value.find('$')))
     437          return value
     438  
     439      def _interpolate_some(self, parser, option, accum, rest, section, map,
     440                            depth):
     441          rawval = parser.get(section, option, raw=True, fallback=rest)
     442          if depth > MAX_INTERPOLATION_DEPTH:
     443              raise InterpolationDepthError(option, section, rawval)
     444          while rest:
     445              p = rest.find("$")
     446              if p < 0:
     447                  accum.append(rest)
     448                  return
     449              if p > 0:
     450                  accum.append(rest[:p])
     451                  rest = rest[p:]
     452              # p is no longer used
     453              c = rest[1:2]
     454              if c == "$":
     455                  accum.append("$")
     456                  rest = rest[2:]
     457              elif c == "{":
     458                  m = self._KEYCRE.match(rest)
     459                  if m is None:
     460                      raise InterpolationSyntaxError(option, section,
     461                          "bad interpolation variable reference %r" % rest)
     462                  path = m.group(1).split(':')
     463                  rest = rest[m.end():]
     464                  sect = section
     465                  opt = option
     466                  try:
     467                      if len(path) == 1:
     468                          opt = parser.optionxform(path[0])
     469                          v = map[opt]
     470                      elif len(path) == 2:
     471                          sect = path[0]
     472                          opt = parser.optionxform(path[1])
     473                          v = parser.get(sect, opt, raw=True)
     474                      else:
     475                          raise InterpolationSyntaxError(
     476                              option, section,
     477                              "More than one ':' found: %r" % (rest,))
     478                  except (KeyError, NoSectionError, NoOptionError):
     479                      raise InterpolationMissingOptionError(
     480                          option, section, rawval, ":".join(path)) from None
     481                  if "$" in v:
     482                      self._interpolate_some(parser, opt, accum, v, sect,
     483                                             dict(parser.items(sect, raw=True)),
     484                                             depth + 1)
     485                  else:
     486                      accum.append(v)
     487              else:
     488                  raise InterpolationSyntaxError(
     489                      option, section,
     490                      "'$' must be followed by '$' or '{', "
     491                      "found: %r" % (rest,))
     492  
     493  
     494  class ESC[4;38;5;81mLegacyInterpolation(ESC[4;38;5;149mInterpolation):
     495      """Deprecated interpolation used in old versions of ConfigParser.
     496      Use BasicInterpolation or ExtendedInterpolation instead."""
     497  
     498      _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
     499  
     500      def __init__(self, *args, **kwargs):
     501          super().__init__(*args, **kwargs)
     502          warnings.warn(
     503              "LegacyInterpolation has been deprecated since Python 3.2 "
     504              "and will be removed from the configparser module in Python 3.13. "
     505              "Use BasicInterpolation or ExtendedInterpolation instead.",
     506              DeprecationWarning, stacklevel=2
     507          )
     508  
     509      def before_get(self, parser, section, option, value, vars):
     510          rawval = value
     511          depth = MAX_INTERPOLATION_DEPTH
     512          while depth:                    # Loop through this until it's done
     513              depth -= 1
     514              if value and "%(" in value:
     515                  replace = functools.partial(self._interpolation_replace,
     516                                              parser=parser)
     517                  value = self._KEYCRE.sub(replace, value)
     518                  try:
     519                      value = value % vars
     520                  except KeyError as e:
     521                      raise InterpolationMissingOptionError(
     522                          option, section, rawval, e.args[0]) from None
     523              else:
     524                  break
     525          if value and "%(" in value:
     526              raise InterpolationDepthError(option, section, rawval)
     527          return value
     528  
     529      def before_set(self, parser, section, option, value):
     530          return value
     531  
     532      @staticmethod
     533      def _interpolation_replace(match, parser):
     534          s = match.group(1)
     535          if s is None:
     536              return match.group()
     537          else:
     538              return "%%(%s)s" % parser.optionxform(s)
     539  
     540  
     541  class ESC[4;38;5;81mRawConfigParser(ESC[4;38;5;149mMutableMapping):
     542      """ConfigParser that does not do interpolation."""
     543  
     544      # Regular expressions for parsing section headers and options
     545      _SECT_TMPL = r"""
     546          \[                                 # [
     547          (?P<header>.+)                     # very permissive!
     548          \]                                 # ]
     549          """
     550      _OPT_TMPL = r"""
     551          (?P<option>.*?)                    # very permissive!
     552          \s*(?P<vi>{delim})\s*              # any number of space/tab,
     553                                             # followed by any of the
     554                                             # allowed delimiters,
     555                                             # followed by any space/tab
     556          (?P<value>.*)$                     # everything up to eol
     557          """
     558      _OPT_NV_TMPL = r"""
     559          (?P<option>.*?)                    # very permissive!
     560          \s*(?:                             # any number of space/tab,
     561          (?P<vi>{delim})\s*                 # optionally followed by
     562                                             # any of the allowed
     563                                             # delimiters, followed by any
     564                                             # space/tab
     565          (?P<value>.*))?$                   # everything up to eol
     566          """
     567      # Interpolation algorithm to be used if the user does not specify another
     568      _DEFAULT_INTERPOLATION = Interpolation()
     569      # Compiled regular expression for matching sections
     570      SECTCRE = re.compile(_SECT_TMPL, re.VERBOSE)
     571      # Compiled regular expression for matching options with typical separators
     572      OPTCRE = re.compile(_OPT_TMPL.format(delim="=|:"), re.VERBOSE)
     573      # Compiled regular expression for matching options with optional values
     574      # delimited using typical separators
     575      OPTCRE_NV = re.compile(_OPT_NV_TMPL.format(delim="=|:"), re.VERBOSE)
     576      # Compiled regular expression for matching leading whitespace in a line
     577      NONSPACECRE = re.compile(r"\S")
     578      # Possible boolean values in the configuration.
     579      BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True,
     580                        '0': False, 'no': False, 'false': False, 'off': False}
     581  
     582      def __init__(self, defaults=None, dict_type=_default_dict,
     583                   allow_no_value=False, *, delimiters=('=', ':'),
     584                   comment_prefixes=('#', ';'), inline_comment_prefixes=None,
     585                   strict=True, empty_lines_in_values=True,
     586                   default_section=DEFAULTSECT,
     587                   interpolation=_UNSET, converters=_UNSET):
     588  
     589          self._dict = dict_type
     590          self._sections = self._dict()
     591          self._defaults = self._dict()
     592          self._converters = ConverterMapping(self)
     593          self._proxies = self._dict()
     594          self._proxies[default_section] = SectionProxy(self, default_section)
     595          self._delimiters = tuple(delimiters)
     596          if delimiters == ('=', ':'):
     597              self._optcre = self.OPTCRE_NV if allow_no_value else self.OPTCRE
     598          else:
     599              d = "|".join(re.escape(d) for d in delimiters)
     600              if allow_no_value:
     601                  self._optcre = re.compile(self._OPT_NV_TMPL.format(delim=d),
     602                                            re.VERBOSE)
     603              else:
     604                  self._optcre = re.compile(self._OPT_TMPL.format(delim=d),
     605                                            re.VERBOSE)
     606          self._comment_prefixes = tuple(comment_prefixes or ())
     607          self._inline_comment_prefixes = tuple(inline_comment_prefixes or ())
     608          self._strict = strict
     609          self._allow_no_value = allow_no_value
     610          self._empty_lines_in_values = empty_lines_in_values
     611          self.default_section=default_section
     612          self._interpolation = interpolation
     613          if self._interpolation is _UNSET:
     614              self._interpolation = self._DEFAULT_INTERPOLATION
     615          if self._interpolation is None:
     616              self._interpolation = Interpolation()
     617          if not isinstance(self._interpolation, Interpolation):
     618              raise TypeError(
     619                  f"interpolation= must be None or an instance of Interpolation;"
     620                  f" got an object of type {type(self._interpolation)}"
     621              )
     622          if converters is not _UNSET:
     623              self._converters.update(converters)
     624          if defaults:
     625              self._read_defaults(defaults)
     626  
     627      def defaults(self):
     628          return self._defaults
     629  
     630      def sections(self):
     631          """Return a list of section names, excluding [DEFAULT]"""
     632          # self._sections will never have [DEFAULT] in it
     633          return list(self._sections.keys())
     634  
     635      def add_section(self, section):
     636          """Create a new section in the configuration.
     637  
     638          Raise DuplicateSectionError if a section by the specified name
     639          already exists. Raise ValueError if name is DEFAULT.
     640          """
     641          if section == self.default_section:
     642              raise ValueError('Invalid section name: %r' % section)
     643  
     644          if section in self._sections:
     645              raise DuplicateSectionError(section)
     646          self._sections[section] = self._dict()
     647          self._proxies[section] = SectionProxy(self, section)
     648  
     649      def has_section(self, section):
     650          """Indicate whether the named section is present in the configuration.
     651  
     652          The DEFAULT section is not acknowledged.
     653          """
     654          return section in self._sections
     655  
     656      def options(self, section):
     657          """Return a list of option names for the given section name."""
     658          try:
     659              opts = self._sections[section].copy()
     660          except KeyError:
     661              raise NoSectionError(section) from None
     662          opts.update(self._defaults)
     663          return list(opts.keys())
     664  
     665      def read(self, filenames, encoding=None):
     666          """Read and parse a filename or an iterable of filenames.
     667  
     668          Files that cannot be opened are silently ignored; this is
     669          designed so that you can specify an iterable of potential
     670          configuration file locations (e.g. current directory, user's
     671          home directory, systemwide directory), and all existing
     672          configuration files in the iterable will be read.  A single
     673          filename may also be given.
     674  
     675          Return list of successfully read files.
     676          """
     677          if isinstance(filenames, (str, bytes, os.PathLike)):
     678              filenames = [filenames]
     679          encoding = io.text_encoding(encoding)
     680          read_ok = []
     681          for filename in filenames:
     682              try:
     683                  with open(filename, encoding=encoding) as fp:
     684                      self._read(fp, filename)
     685              except OSError:
     686                  continue
     687              if isinstance(filename, os.PathLike):
     688                  filename = os.fspath(filename)
     689              read_ok.append(filename)
     690          return read_ok
     691  
     692      def read_file(self, f, source=None):
     693          """Like read() but the argument must be a file-like object.
     694  
     695          The `f` argument must be iterable, returning one line at a time.
     696          Optional second argument is the `source` specifying the name of the
     697          file being read. If not given, it is taken from f.name. If `f` has no
     698          `name` attribute, `<???>` is used.
     699          """
     700          if source is None:
     701              try:
     702                  source = f.name
     703              except AttributeError:
     704                  source = '<???>'
     705          self._read(f, source)
     706  
     707      def read_string(self, string, source='<string>'):
     708          """Read configuration from a given string."""
     709          sfile = io.StringIO(string)
     710          self.read_file(sfile, source)
     711  
     712      def read_dict(self, dictionary, source='<dict>'):
     713          """Read configuration from a dictionary.
     714  
     715          Keys are section names, values are dictionaries with keys and values
     716          that should be present in the section. If the used dictionary type
     717          preserves order, sections and their keys will be added in order.
     718  
     719          All types held in the dictionary are converted to strings during
     720          reading, including section names, option names and keys.
     721  
     722          Optional second argument is the `source` specifying the name of the
     723          dictionary being read.
     724          """
     725          elements_added = set()
     726          for section, keys in dictionary.items():
     727              section = str(section)
     728              try:
     729                  self.add_section(section)
     730              except (DuplicateSectionError, ValueError):
     731                  if self._strict and section in elements_added:
     732                      raise
     733              elements_added.add(section)
     734              for key, value in keys.items():
     735                  key = self.optionxform(str(key))
     736                  if value is not None:
     737                      value = str(value)
     738                  if self._strict and (section, key) in elements_added:
     739                      raise DuplicateOptionError(section, key, source)
     740                  elements_added.add((section, key))
     741                  self.set(section, key, value)
     742  
     743      def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
     744          """Get an option value for a given section.
     745  
     746          If `vars` is provided, it must be a dictionary. The option is looked up
     747          in `vars` (if provided), `section`, and in `DEFAULTSECT` in that order.
     748          If the key is not found and `fallback` is provided, it is used as
     749          a fallback value. `None` can be provided as a `fallback` value.
     750  
     751          If interpolation is enabled and the optional argument `raw` is False,
     752          all interpolations are expanded in the return values.
     753  
     754          Arguments `raw`, `vars`, and `fallback` are keyword only.
     755  
     756          The section DEFAULT is special.
     757          """
     758          try:
     759              d = self._unify_values(section, vars)
     760          except NoSectionError:
     761              if fallback is _UNSET:
     762                  raise
     763              else:
     764                  return fallback
     765          option = self.optionxform(option)
     766          try:
     767              value = d[option]
     768          except KeyError:
     769              if fallback is _UNSET:
     770                  raise NoOptionError(option, section)
     771              else:
     772                  return fallback
     773  
     774          if raw or value is None:
     775              return value
     776          else:
     777              return self._interpolation.before_get(self, section, option, value,
     778                                                    d)
     779  
     780      def _get(self, section, conv, option, **kwargs):
     781          return conv(self.get(section, option, **kwargs))
     782  
     783      def _get_conv(self, section, option, conv, *, raw=False, vars=None,
     784                    fallback=_UNSET, **kwargs):
     785          try:
     786              return self._get(section, conv, option, raw=raw, vars=vars,
     787                               **kwargs)
     788          except (NoSectionError, NoOptionError):
     789              if fallback is _UNSET:
     790                  raise
     791              return fallback
     792  
     793      # getint, getfloat and getboolean provided directly for backwards compat
     794      def getint(self, section, option, *, raw=False, vars=None,
     795                 fallback=_UNSET, **kwargs):
     796          return self._get_conv(section, option, int, raw=raw, vars=vars,
     797                                fallback=fallback, **kwargs)
     798  
     799      def getfloat(self, section, option, *, raw=False, vars=None,
     800                   fallback=_UNSET, **kwargs):
     801          return self._get_conv(section, option, float, raw=raw, vars=vars,
     802                                fallback=fallback, **kwargs)
     803  
     804      def getboolean(self, section, option, *, raw=False, vars=None,
     805                     fallback=_UNSET, **kwargs):
     806          return self._get_conv(section, option, self._convert_to_boolean,
     807                                raw=raw, vars=vars, fallback=fallback, **kwargs)
     808  
     809      def items(self, section=_UNSET, raw=False, vars=None):
     810          """Return a list of (name, value) tuples for each option in a section.
     811  
     812          All % interpolations are expanded in the return values, based on the
     813          defaults passed into the constructor, unless the optional argument
     814          `raw` is true.  Additional substitutions may be provided using the
     815          `vars` argument, which must be a dictionary whose contents overrides
     816          any pre-existing defaults.
     817  
     818          The section DEFAULT is special.
     819          """
     820          if section is _UNSET:
     821              return super().items()
     822          d = self._defaults.copy()
     823          try:
     824              d.update(self._sections[section])
     825          except KeyError:
     826              if section != self.default_section:
     827                  raise NoSectionError(section)
     828          orig_keys = list(d.keys())
     829          # Update with the entry specific variables
     830          if vars:
     831              for key, value in vars.items():
     832                  d[self.optionxform(key)] = value
     833          value_getter = lambda option: self._interpolation.before_get(self,
     834              section, option, d[option], d)
     835          if raw:
     836              value_getter = lambda option: d[option]
     837          return [(option, value_getter(option)) for option in orig_keys]
     838  
     839      def popitem(self):
     840          """Remove a section from the parser and return it as
     841          a (section_name, section_proxy) tuple. If no section is present, raise
     842          KeyError.
     843  
     844          The section DEFAULT is never returned because it cannot be removed.
     845          """
     846          for key in self.sections():
     847              value = self[key]
     848              del self[key]
     849              return key, value
     850          raise KeyError
     851  
     852      def optionxform(self, optionstr):
     853          return optionstr.lower()
     854  
     855      def has_option(self, section, option):
     856          """Check for the existence of a given option in a given section.
     857          If the specified `section` is None or an empty string, DEFAULT is
     858          assumed. If the specified `section` does not exist, returns False."""
     859          if not section or section == self.default_section:
     860              option = self.optionxform(option)
     861              return option in self._defaults
     862          elif section not in self._sections:
     863              return False
     864          else:
     865              option = self.optionxform(option)
     866              return (option in self._sections[section]
     867                      or option in self._defaults)
     868  
     869      def set(self, section, option, value=None):
     870          """Set an option."""
     871          if value:
     872              value = self._interpolation.before_set(self, section, option,
     873                                                     value)
     874          if not section or section == self.default_section:
     875              sectdict = self._defaults
     876          else:
     877              try:
     878                  sectdict = self._sections[section]
     879              except KeyError:
     880                  raise NoSectionError(section) from None
     881          sectdict[self.optionxform(option)] = value
     882  
     883      def write(self, fp, space_around_delimiters=True):
     884          """Write an .ini-format representation of the configuration state.
     885  
     886          If `space_around_delimiters` is True (the default), delimiters
     887          between keys and values are surrounded by spaces.
     888  
     889          Please note that comments in the original configuration file are not
     890          preserved when writing the configuration back.
     891          """
     892          if space_around_delimiters:
     893              d = " {} ".format(self._delimiters[0])
     894          else:
     895              d = self._delimiters[0]
     896          if self._defaults:
     897              self._write_section(fp, self.default_section,
     898                                      self._defaults.items(), d)
     899          for section in self._sections:
     900              self._write_section(fp, section,
     901                                  self._sections[section].items(), d)
     902  
     903      def _write_section(self, fp, section_name, section_items, delimiter):
     904          """Write a single section to the specified `fp`."""
     905          fp.write("[{}]\n".format(section_name))
     906          for key, value in section_items:
     907              value = self._interpolation.before_write(self, section_name, key,
     908                                                       value)
     909              if value is not None or not self._allow_no_value:
     910                  value = delimiter + str(value).replace('\n', '\n\t')
     911              else:
     912                  value = ""
     913              fp.write("{}{}\n".format(key, value))
     914          fp.write("\n")
     915  
     916      def remove_option(self, section, option):
     917          """Remove an option."""
     918          if not section or section == self.default_section:
     919              sectdict = self._defaults
     920          else:
     921              try:
     922                  sectdict = self._sections[section]
     923              except KeyError:
     924                  raise NoSectionError(section) from None
     925          option = self.optionxform(option)
     926          existed = option in sectdict
     927          if existed:
     928              del sectdict[option]
     929          return existed
     930  
     931      def remove_section(self, section):
     932          """Remove a file section."""
     933          existed = section in self._sections
     934          if existed:
     935              del self._sections[section]
     936              del self._proxies[section]
     937          return existed
     938  
     939      def __getitem__(self, key):
     940          if key != self.default_section and not self.has_section(key):
     941              raise KeyError(key)
     942          return self._proxies[key]
     943  
     944      def __setitem__(self, key, value):
     945          # To conform with the mapping protocol, overwrites existing values in
     946          # the section.
     947          if key in self and self[key] is value:
     948              return
     949          # XXX this is not atomic if read_dict fails at any point. Then again,
     950          # no update method in configparser is atomic in this implementation.
     951          if key == self.default_section:
     952              self._defaults.clear()
     953          elif key in self._sections:
     954              self._sections[key].clear()
     955          self.read_dict({key: value})
     956  
     957      def __delitem__(self, key):
     958          if key == self.default_section:
     959              raise ValueError("Cannot remove the default section.")
     960          if not self.has_section(key):
     961              raise KeyError(key)
     962          self.remove_section(key)
     963  
     964      def __contains__(self, key):
     965          return key == self.default_section or self.has_section(key)
     966  
     967      def __len__(self):
     968          return len(self._sections) + 1 # the default section
     969  
     970      def __iter__(self):
     971          # XXX does it break when underlying container state changed?
     972          return itertools.chain((self.default_section,), self._sections.keys())
     973  
     974      def _read(self, fp, fpname):
     975          """Parse a sectioned configuration file.
     976  
     977          Each section in a configuration file contains a header, indicated by
     978          a name in square brackets (`[]`), plus key/value options, indicated by
     979          `name` and `value` delimited with a specific substring (`=` or `:` by
     980          default).
     981  
     982          Values can span multiple lines, as long as they are indented deeper
     983          than the first line of the value. Depending on the parser's mode, blank
     984          lines may be treated as parts of multiline values or ignored.
     985  
     986          Configuration files may include comments, prefixed by specific
     987          characters (`#` and `;` by default). Comments may appear on their own
     988          in an otherwise empty line or may be entered in lines holding values or
     989          section names. Please note that comments get stripped off when reading configuration files.
     990          """
     991          elements_added = set()
     992          cursect = None                        # None, or a dictionary
     993          sectname = None
     994          optname = None
     995          lineno = 0
     996          indent_level = 0
     997          e = None                              # None, or an exception
     998          for lineno, line in enumerate(fp, start=1):
     999              comment_start = sys.maxsize
    1000              # strip inline comments
    1001              inline_prefixes = {p: -1 for p in self._inline_comment_prefixes}
    1002              while comment_start == sys.maxsize and inline_prefixes:
    1003                  next_prefixes = {}
    1004                  for prefix, index in inline_prefixes.items():
    1005                      index = line.find(prefix, index+1)
    1006                      if index == -1:
    1007                          continue
    1008                      next_prefixes[prefix] = index
    1009                      if index == 0 or (index > 0 and line[index-1].isspace()):
    1010                          comment_start = min(comment_start, index)
    1011                  inline_prefixes = next_prefixes
    1012              # strip full line comments
    1013              for prefix in self._comment_prefixes:
    1014                  if line.strip().startswith(prefix):
    1015                      comment_start = 0
    1016                      break
    1017              if comment_start == sys.maxsize:
    1018                  comment_start = None
    1019              value = line[:comment_start].strip()
    1020              if not value:
    1021                  if self._empty_lines_in_values:
    1022                      # add empty line to the value, but only if there was no
    1023                      # comment on the line
    1024                      if (comment_start is None and
    1025                          cursect is not None and
    1026                          optname and
    1027                          cursect[optname] is not None):
    1028                          cursect[optname].append('') # newlines added at join
    1029                  else:
    1030                      # empty line marks end of value
    1031                      indent_level = sys.maxsize
    1032                  continue
    1033              # continuation line?
    1034              first_nonspace = self.NONSPACECRE.search(line)
    1035              cur_indent_level = first_nonspace.start() if first_nonspace else 0
    1036              if (cursect is not None and optname and
    1037                  cur_indent_level > indent_level):
    1038                  cursect[optname].append(value)
    1039              # a section header or option header?
    1040              else:
    1041                  indent_level = cur_indent_level
    1042                  # is it a section header?
    1043                  mo = self.SECTCRE.match(value)
    1044                  if mo:
    1045                      sectname = mo.group('header')
    1046                      if sectname in self._sections:
    1047                          if self._strict and sectname in elements_added:
    1048                              raise DuplicateSectionError(sectname, fpname,
    1049                                                          lineno)
    1050                          cursect = self._sections[sectname]
    1051                          elements_added.add(sectname)
    1052                      elif sectname == self.default_section:
    1053                          cursect = self._defaults
    1054                      else:
    1055                          cursect = self._dict()
    1056                          self._sections[sectname] = cursect
    1057                          self._proxies[sectname] = SectionProxy(self, sectname)
    1058                          elements_added.add(sectname)
    1059                      # So sections can't start with a continuation line
    1060                      optname = None
    1061                  # no section header in the file?
    1062                  elif cursect is None:
    1063                      raise MissingSectionHeaderError(fpname, lineno, line)
    1064                  # an option line?
    1065                  else:
    1066                      mo = self._optcre.match(value)
    1067                      if mo:
    1068                          optname, vi, optval = mo.group('option', 'vi', 'value')
    1069                          if not optname:
    1070                              e = self._handle_error(e, fpname, lineno, line)
    1071                          optname = self.optionxform(optname.rstrip())
    1072                          if (self._strict and
    1073                              (sectname, optname) in elements_added):
    1074                              raise DuplicateOptionError(sectname, optname,
    1075                                                         fpname, lineno)
    1076                          elements_added.add((sectname, optname))
    1077                          # This check is fine because the OPTCRE cannot
    1078                          # match if it would set optval to None
    1079                          if optval is not None:
    1080                              optval = optval.strip()
    1081                              cursect[optname] = [optval]
    1082                          else:
    1083                              # valueless option handling
    1084                              cursect[optname] = None
    1085                      else:
    1086                          # a non-fatal parsing error occurred. set up the
    1087                          # exception but keep going. the exception will be
    1088                          # raised at the end of the file and will contain a
    1089                          # list of all bogus lines
    1090                          e = self._handle_error(e, fpname, lineno, line)
    1091          self._join_multiline_values()
    1092          # if any parsing errors occurred, raise an exception
    1093          if e:
    1094              raise e
    1095  
    1096      def _join_multiline_values(self):
    1097          defaults = self.default_section, self._defaults
    1098          all_sections = itertools.chain((defaults,),
    1099                                         self._sections.items())
    1100          for section, options in all_sections:
    1101              for name, val in options.items():
    1102                  if isinstance(val, list):
    1103                      val = '\n'.join(val).rstrip()
    1104                  options[name] = self._interpolation.before_read(self,
    1105                                                                  section,
    1106                                                                  name, val)
    1107  
    1108      def _read_defaults(self, defaults):
    1109          """Read the defaults passed in the initializer.
    1110          Note: values can be non-string."""
    1111          for key, value in defaults.items():
    1112              self._defaults[self.optionxform(key)] = value
    1113  
    1114      def _handle_error(self, exc, fpname, lineno, line):
    1115          if not exc:
    1116              exc = ParsingError(fpname)
    1117          exc.append(lineno, repr(line))
    1118          return exc
    1119  
    1120      def _unify_values(self, section, vars):
    1121          """Create a sequence of lookups with 'vars' taking priority over
    1122          the 'section' which takes priority over the DEFAULTSECT.
    1123  
    1124          """
    1125          sectiondict = {}
    1126          try:
    1127              sectiondict = self._sections[section]
    1128          except KeyError:
    1129              if section != self.default_section:
    1130                  raise NoSectionError(section) from None
    1131          # Update with the entry specific variables
    1132          vardict = {}
    1133          if vars:
    1134              for key, value in vars.items():
    1135                  if value is not None:
    1136                      value = str(value)
    1137                  vardict[self.optionxform(key)] = value
    1138          return _ChainMap(vardict, sectiondict, self._defaults)
    1139  
    1140      def _convert_to_boolean(self, value):
    1141          """Return a boolean value translating from other types if necessary.
    1142          """
    1143          if value.lower() not in self.BOOLEAN_STATES:
    1144              raise ValueError('Not a boolean: %s' % value)
    1145          return self.BOOLEAN_STATES[value.lower()]
    1146  
    1147      def _validate_value_types(self, *, section="", option="", value=""):
    1148          """Raises a TypeError for non-string values.
    1149  
    1150          The only legal non-string value if we allow valueless
    1151          options is None, so we need to check if the value is a
    1152          string if:
    1153          - we do not allow valueless options, or
    1154          - we allow valueless options but the value is not None
    1155  
    1156          For compatibility reasons this method is not used in classic set()
    1157          for RawConfigParsers. It is invoked in every case for mapping protocol
    1158          access and in ConfigParser.set().
    1159          """
    1160          if not isinstance(section, str):
    1161              raise TypeError("section names must be strings")
    1162          if not isinstance(option, str):
    1163              raise TypeError("option keys must be strings")
    1164          if not self._allow_no_value or value:
    1165              if not isinstance(value, str):
    1166                  raise TypeError("option values must be strings")
    1167  
    1168      @property
    1169      def converters(self):
    1170          return self._converters
    1171  
    1172  
    1173  class ESC[4;38;5;81mConfigParser(ESC[4;38;5;149mRawConfigParser):
    1174      """ConfigParser implementing interpolation."""
    1175  
    1176      _DEFAULT_INTERPOLATION = BasicInterpolation()
    1177  
    1178      def set(self, section, option, value=None):
    1179          """Set an option.  Extends RawConfigParser.set by validating type and
    1180          interpolation syntax on the value."""
    1181          self._validate_value_types(option=option, value=value)
    1182          super().set(section, option, value)
    1183  
    1184      def add_section(self, section):
    1185          """Create a new section in the configuration.  Extends
    1186          RawConfigParser.add_section by validating if the section name is
    1187          a string."""
    1188          self._validate_value_types(section=section)
    1189          super().add_section(section)
    1190  
    1191      def _read_defaults(self, defaults):
    1192          """Reads the defaults passed in the initializer, implicitly converting
    1193          values to strings like the rest of the API.
    1194  
    1195          Does not perform interpolation for backwards compatibility.
    1196          """
    1197          try:
    1198              hold_interpolation = self._interpolation
    1199              self._interpolation = Interpolation()
    1200              self.read_dict({self.default_section: defaults})
    1201          finally:
    1202              self._interpolation = hold_interpolation
    1203  
    1204  
    1205  class ESC[4;38;5;81mSectionProxy(ESC[4;38;5;149mMutableMapping):
    1206      """A proxy for a single section from a parser."""
    1207  
    1208      def __init__(self, parser, name):
    1209          """Creates a view on a section of the specified `name` in `parser`."""
    1210          self._parser = parser
    1211          self._name = name
    1212          for conv in parser.converters:
    1213              key = 'get' + conv
    1214              getter = functools.partial(self.get, _impl=getattr(parser, key))
    1215              setattr(self, key, getter)
    1216  
    1217      def __repr__(self):
    1218          return '<Section: {}>'.format(self._name)
    1219  
    1220      def __getitem__(self, key):
    1221          if not self._parser.has_option(self._name, key):
    1222              raise KeyError(key)
    1223          return self._parser.get(self._name, key)
    1224  
    1225      def __setitem__(self, key, value):
    1226          self._parser._validate_value_types(option=key, value=value)
    1227          return self._parser.set(self._name, key, value)
    1228  
    1229      def __delitem__(self, key):
    1230          if not (self._parser.has_option(self._name, key) and
    1231                  self._parser.remove_option(self._name, key)):
    1232              raise KeyError(key)
    1233  
    1234      def __contains__(self, key):
    1235          return self._parser.has_option(self._name, key)
    1236  
    1237      def __len__(self):
    1238          return len(self._options())
    1239  
    1240      def __iter__(self):
    1241          return self._options().__iter__()
    1242  
    1243      def _options(self):
    1244          if self._name != self._parser.default_section:
    1245              return self._parser.options(self._name)
    1246          else:
    1247              return self._parser.defaults()
    1248  
    1249      @property
    1250      def parser(self):
    1251          # The parser object of the proxy is read-only.
    1252          return self._parser
    1253  
    1254      @property
    1255      def name(self):
    1256          # The name of the section on a proxy is read-only.
    1257          return self._name
    1258  
    1259      def get(self, option, fallback=None, *, raw=False, vars=None,
    1260              _impl=None, **kwargs):
    1261          """Get an option value.
    1262  
    1263          Unless `fallback` is provided, `None` will be returned if the option
    1264          is not found.
    1265  
    1266          """
    1267          # If `_impl` is provided, it should be a getter method on the parser
    1268          # object that provides the desired type conversion.
    1269          if not _impl:
    1270              _impl = self._parser.get
    1271          return _impl(self._name, option, raw=raw, vars=vars,
    1272                       fallback=fallback, **kwargs)
    1273  
    1274  
    1275  class ESC[4;38;5;81mConverterMapping(ESC[4;38;5;149mMutableMapping):
    1276      """Enables reuse of get*() methods between the parser and section proxies.
    1277  
    1278      If a parser class implements a getter directly, the value for the given
    1279      key will be ``None``. The presence of the converter name here enables
    1280      section proxies to find and use the implementation on the parser class.
    1281      """
    1282  
    1283      GETTERCRE = re.compile(r"^get(?P<name>.+)$")
    1284  
    1285      def __init__(self, parser):
    1286          self._parser = parser
    1287          self._data = {}
    1288          for getter in dir(self._parser):
    1289              m = self.GETTERCRE.match(getter)
    1290              if not m or not callable(getattr(self._parser, getter)):
    1291                  continue
    1292              self._data[m.group('name')] = None   # See class docstring.
    1293  
    1294      def __getitem__(self, key):
    1295          return self._data[key]
    1296  
    1297      def __setitem__(self, key, value):
    1298          try:
    1299              k = 'get' + key
    1300          except TypeError:
    1301              raise ValueError('Incompatible key: {} (type: {})'
    1302                               ''.format(key, type(key)))
    1303          if k == 'get':
    1304              raise ValueError('Incompatible key: cannot use "" as a name')
    1305          self._data[key] = value
    1306          func = functools.partial(self._parser._get_conv, conv=value)
    1307          func.converter = value
    1308          setattr(self._parser, k, func)
    1309          for proxy in self._parser.values():
    1310              getter = functools.partial(proxy.get, _impl=func)
    1311              setattr(proxy, k, getter)
    1312  
    1313      def __delitem__(self, key):
    1314          try:
    1315              k = 'get' + (key or None)
    1316          except TypeError:
    1317              raise KeyError(key)
    1318          del self._data[key]
    1319          for inst in itertools.chain((self._parser,), self._parser.values()):
    1320              try:
    1321                  delattr(inst, k)
    1322              except AttributeError:
    1323                  # don't raise since the entry was present in _data, silently
    1324                  # clean up
    1325                  continue
    1326  
    1327      def __iter__(self):
    1328          return iter(self._data)
    1329  
    1330      def __len__(self):
    1331          return len(self._data)