Skip to content

Commit 1dce000

Browse files
committed
Merged parser.clean() fix (issue #16820) from 3.2 through 3.3.
2 parents 641bb66 + 0dc5ab4 commit 1dce000

4 files changed

Lines changed: 48 additions & 1 deletion

File tree

Doc/library/configparser.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,13 @@ However, there are a few differences that should be taken into account:
389389
the default value to be visible again. Trying to delete a default value
390390
causes a ``KeyError``.
391391

392-
* Trying to delete the ``DEFAULTSECT`` raises ``ValueError``.
392+
* ``DEFAULTSECT`` cannot be removed from the parser:
393+
394+
* trying to delete it raises ``ValueError``,
395+
396+
* ``parser.clear()`` leaves it intact,
397+
398+
* ``parser.popitem()`` never returns it.
393399

394400
* ``parser.get(section, option, **kwargs)`` - the second argument is **not**
395401
a fallback value. Note however that the section-level ``get()`` methods are

Lib/configparser.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,19 @@ def items(self, section=_UNSET, raw=False, vars=None):
852852
value_getter = lambda option: d[option]
853853
return [(option, value_getter(option)) for option in d.keys()]
854854

855+
def popitem(self):
856+
"""Remove a section from the parser and return it as
857+
a (section_name, section_proxy) tuple. If no section is present, raise
858+
KeyError.
859+
860+
The section DEFAULT is never returned because it cannot be removed.
861+
"""
862+
for key in self.sections():
863+
value = self[key]
864+
del self[key]
865+
return key, value
866+
raise KeyError
867+
855868
def optionxform(self, optionstr):
856869
return optionstr.lower()
857870

Lib/test/test_configparser.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,33 @@ def check_items_config(self, expected):
770770
with self.assertRaises(configparser.NoSectionError):
771771
cf.items("no such section")
772772

773+
def test_popitem(self):
774+
cf = self.fromstring("""
775+
[section1]
776+
name1 {0[0]} value1
777+
[section2]
778+
name2 {0[0]} value2
779+
[section3]
780+
name3 {0[0]} value3
781+
""".format(self.delimiters), defaults={"default": "<default>"})
782+
self.assertEqual(cf.popitem()[0], 'section1')
783+
self.assertEqual(cf.popitem()[0], 'section2')
784+
self.assertEqual(cf.popitem()[0], 'section3')
785+
with self.assertRaises(KeyError):
786+
cf.popitem()
787+
788+
def test_clear(self):
789+
cf = self.newconfig({"foo": "Bar"})
790+
self.assertEqual(
791+
cf.get(self.default_section, "Foo"), "Bar",
792+
"could not locate option, expecting case-insensitive option names")
793+
cf['zing'] = {'option1': 'value1', 'option2': 'value2'}
794+
self.assertEqual(cf.sections(), ['zing'])
795+
self.assertEqual(set(cf['zing'].keys()), {'option1', 'option2', 'foo'})
796+
cf.clear()
797+
self.assertEqual(set(cf.sections()), set())
798+
self.assertEqual(set(cf[self.default_section].keys()), {'foo'})
799+
773800

774801
class StrictTestCase(BasicTestCase):
775802
config_class = configparser.RawConfigParser

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,7 @@ Michael Scharf
10571057
Andreas Schawo
10581058
Neil Schemenauer
10591059
David Scherer
1060+
Wolfgang Scherer
10601061
Hynek Schlawack
10611062
Bob Schmertz
10621063
Gregor Schmid

0 commit comments

Comments
 (0)