Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 71b37a5

Browse files
committed
100% test coverage, better mapping protocol compatibility, some minor bugfixes
1 parent 0e74cac commit 71b37a5

4 files changed

Lines changed: 317 additions & 88 deletions

File tree

Doc/library/configparser.rst

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -391,17 +391,20 @@ However, there are a few differences that should be taken into account:
391391

392392
* Trying to delete the ``DEFAULTSECT`` raises ``ValueError``.
393393

394-
* There are two parser-level methods in the legacy API that hide the dictionary
395-
interface and are incompatible:
394+
* ``parser.get(section, option, **kwargs)`` - the second argument is **not**
395+
a fallback value. Note however that the section-level ``get()`` methods are
396+
compatible both with the mapping protocol and the classic configparser API.
396397

397-
* ``parser.get(section, option, **kwargs)`` - the second argument is **not** a
398-
fallback value
399-
400-
* ``parser.items(section)`` - this returns a list of *option*, *value* pairs
401-
for a specified ``section``
398+
* ``parser.items()`` is compatible with the mapping protocol (returns a list of
399+
*section_name*, *section_proxy* pairs including the DEFAULTSECT). However,
400+
this method can also be invoked with arguments: ``parser.items(section, raw,
401+
vars)``. The latter call returns a list of *option*, *value* pairs for
402+
a specified ``section``, with all interpolations expanded (unless
403+
``raw=True`` is provided).
402404

403405
The mapping protocol is implemented on top of the existing legacy API so that
404-
subclassing the original interface makes the mappings work as expected as well.
406+
subclasses overriding the original interface still should have mappings working
407+
as expected.
405408

406409

407410
Customizing Parser Behaviour
@@ -906,7 +909,8 @@ ConfigParser Objects
906909
.. method:: has_option(section, option)
907910

908911
If the given *section* exists, and contains the given *option*, return
909-
:const:`True`; otherwise return :const:`False`.
912+
:const:`True`; otherwise return :const:`False`. If the specified
913+
*section* is :const:`None` or an empty string, DEFAULT is assumed.
910914

911915

912916
.. method:: read(filenames, encoding=None)
@@ -964,14 +968,17 @@ ConfigParser Objects
964968

965969
.. method:: read_dict(dictionary, source='<dict>')
966970

967-
Load configuration from a dictionary. Keys are section names, values are
968-
dictionaries with keys and values that should be present in the section.
969-
If the used dictionary type preserves order, sections and their keys will
970-
be added in order. Values are automatically converted to strings.
971+
Load configuration from any object that provides a dict-like ``items()``
972+
method. Keys are section names, values are dictionaries with keys and
973+
values that should be present in the section. If the used dictionary
974+
type preserves order, sections and their keys will be added in order.
975+
Values are automatically converted to strings.
971976

972977
Optional argument *source* specifies a context-specific name of the
973978
dictionary passed. If not given, ``<dict>`` is used.
974979

980+
This method can be used to copy state between parsers.
981+
975982
.. versionadded:: 3.2
976983

977984

@@ -1019,10 +1026,13 @@ ConfigParser Objects
10191026
*fallback*.
10201027

10211028

1022-
.. method:: items(section, raw=False, vars=None)
1029+
.. method:: items([section], raw=False, vars=None)
1030+
1031+
When *section* is not given, return a list of *section_name*,
1032+
*section_proxy* pairs, including DEFAULTSECT.
10231033

1024-
Return a list of *name*, *value* pairs for the options in the given
1025-
*section*. Optional arguments have the same meaning as for the
1034+
Otherwise, return a list of *name*, *value* pairs for the options in the
1035+
given *section*. Optional arguments have the same meaning as for the
10261036
:meth:`get` method.
10271037

10281038

Lib/configparser.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,10 @@
9898
insensitively defined as 0, false, no, off for False, and 1, true,
9999
yes, on for True). Returns False or True.
100100
101-
items(section, raw=False, vars=None)
102-
Return a list of tuples with (name, value) for each option
101+
items(section=_UNSET, raw=False, vars=None)
102+
If section is given, return a list of tuples with (section_name,
103+
section_proxy) for each section, including DEFAULTSECT. Otherwise,
104+
return a list of tuples with (name, value) for each option
103105
in the section.
104106
105107
remove_section(section)
@@ -495,9 +497,9 @@ def _interpolate_some(self, parser, option, accum, rest, section, map,
495497
raise InterpolationSyntaxError(
496498
option, section,
497499
"More than one ':' found: %r" % (rest,))
498-
except KeyError:
500+
except (KeyError, NoSectionError, NoOptionError):
499501
raise InterpolationMissingOptionError(
500-
option, section, rest, var)
502+
option, section, rest, ":".join(path))
501503
if "$" in v:
502504
self._interpolate_some(parser, opt, accum, v, sect,
503505
dict(parser.items(sect, raw=True)),
@@ -730,7 +732,7 @@ def read_dict(self, dictionary, source='<dict>'):
730732
except (DuplicateSectionError, ValueError):
731733
if self._strict and section in elements_added:
732734
raise
733-
elements_added.add(section)
735+
elements_added.add(section)
734736
for key, value in keys.items():
735737
key = self.optionxform(str(key))
736738
if value is not None:
@@ -820,7 +822,7 @@ def getboolean(self, section, option, *, raw=False, vars=None,
820822
else:
821823
return fallback
822824

823-
def items(self, section, raw=False, vars=None):
825+
def items(self, section=_UNSET, raw=False, vars=None):
824826
"""Return a list of (name, value) tuples for each option in a section.
825827
826828
All % interpolations are expanded in the return values, based on the
@@ -831,6 +833,8 @@ def items(self, section, raw=False, vars=None):
831833
832834
The section DEFAULT is special.
833835
"""
836+
if section is _UNSET:
837+
return super().items()
834838
d = self._defaults.copy()
835839
try:
836840
d.update(self._sections[section])
@@ -851,7 +855,9 @@ def optionxform(self, optionstr):
851855
return optionstr.lower()
852856

853857
def has_option(self, section, option):
854-
"""Check for the existence of a given option in a given section."""
858+
"""Check for the existence of a given option in a given section.
859+
If the specified `section' is None or an empty string, DEFAULT is
860+
assumed. If the specified `section' does not exist, returns False."""
855861
if not section or section == self.default_section:
856862
option = self.optionxform(option)
857863
return option in self._defaults
@@ -1059,9 +1065,6 @@ def _read(self, fp, fpname):
10591065
# match if it would set optval to None
10601066
if optval is not None:
10611067
optval = optval.strip()
1062-
# allow empty values
1063-
if optval == '""':
1064-
optval = ''
10651068
cursect[optname] = [optval]
10661069
else:
10671070
# valueless option handling
@@ -1196,21 +1199,24 @@ def __setitem__(self, key, value):
11961199
return self._parser.set(self._name, key, value)
11971200

11981201
def __delitem__(self, key):
1199-
if not self._parser.has_option(self._name, key):
1202+
if not (self._parser.has_option(self._name, key) and
1203+
self._parser.remove_option(self._name, key)):
12001204
raise KeyError(key)
1201-
return self._parser.remove_option(self._name, key)
12021205

12031206
def __contains__(self, key):
12041207
return self._parser.has_option(self._name, key)
12051208

12061209
def __len__(self):
1207-
# XXX weak performance
1208-
return len(self._parser.options(self._name))
1210+
return len(self._options())
12091211

12101212
def __iter__(self):
1211-
# XXX weak performance
1212-
# XXX does not break when underlying container state changed
1213-
return self._parser.options(self._name).__iter__()
1213+
return self._options().__iter__()
1214+
1215+
def _options(self):
1216+
if self._name != self._parser.default_section:
1217+
return self._parser.options(self._name)
1218+
else:
1219+
return self._parser.defaults()
12141220

12151221
def get(self, option, fallback=None, *, raw=False, vars=None):
12161222
return self._parser.get(self._name, option, raw=raw, vars=vars,

0 commit comments

Comments
 (0)