mirror of https://github.com/python/cpython
bpo-23835: Restore legacy defaults= behavior for RawConfigParser (#3191)
The fix for bpo-23835 fixed ConfigParser behavior in defaults= handling. Unfortunately, it caused a backwards compatibility regression with RawConfigParser objects which allow for non-string values. This commit restores the legacy behavior for RawConfigParser only.
This commit is contained in:
parent
a6296d34a4
commit
a5fab17fc1
|
@ -1213,8 +1213,10 @@ RawConfigParser Objects
|
|||
default_section=configparser.DEFAULTSECT[, \
|
||||
interpolation])
|
||||
|
||||
Legacy variant of the :class:`ConfigParser` with interpolation disabled
|
||||
by default and unsafe ``add_section`` and ``set`` methods.
|
||||
Legacy variant of the :class:`ConfigParser`. It has interpolation
|
||||
disabled by default and allows for non-string section names, option
|
||||
names, and values via its unsafe ``add_section`` and ``set`` methods,
|
||||
as well as the legacy ``defaults=`` keyword argument handling.
|
||||
|
||||
.. note::
|
||||
Consider using :class:`ConfigParser` instead which checks types of
|
||||
|
|
|
@ -635,7 +635,7 @@ class RawConfigParser(MutableMapping):
|
|||
if converters is not _UNSET:
|
||||
self._converters.update(converters)
|
||||
if defaults:
|
||||
self.read_dict({default_section: defaults})
|
||||
self._read_defaults(defaults)
|
||||
|
||||
def defaults(self):
|
||||
return self._defaults
|
||||
|
@ -1121,6 +1121,12 @@ class RawConfigParser(MutableMapping):
|
|||
section,
|
||||
name, val)
|
||||
|
||||
def _read_defaults(self, defaults):
|
||||
"""Read the defaults passed in the initializer.
|
||||
Note: values can be non-string."""
|
||||
for key, value in defaults.items():
|
||||
self._defaults[self.optionxform(key)] = value
|
||||
|
||||
def _handle_error(self, exc, fpname, lineno, line):
|
||||
if not exc:
|
||||
exc = ParsingError(fpname)
|
||||
|
@ -1198,6 +1204,11 @@ class ConfigParser(RawConfigParser):
|
|||
self._validate_value_types(section=section)
|
||||
super().add_section(section)
|
||||
|
||||
def _read_defaults(self, defaults):
|
||||
"""Reads the defaults passed in the initializer, implicitly converting
|
||||
values to strings like the rest of the API."""
|
||||
self.read_dict({self.default_section: defaults})
|
||||
|
||||
|
||||
class SafeConfigParser(ConfigParser):
|
||||
"""ConfigParser alias for backwards compatibility purposes."""
|
||||
|
|
|
@ -855,15 +855,6 @@ boolean {0[0]} NO
|
|||
self.assertEqual(cf.get('DEFAULT', 'test'), 'test')
|
||||
self.assertEqual(cf['DEFAULT']['test'], 'test')
|
||||
|
||||
def test_defaults_keyword(self):
|
||||
# test that bpo-23835 is fixed
|
||||
cf = self.newconfig(defaults={1: 2.4})
|
||||
self.assertEqual(cf[self.default_section]['1'], '2.4')
|
||||
self.assertAlmostEqual(cf[self.default_section].getfloat('1'), 2.4)
|
||||
cf = self.newconfig(defaults={"A": 5.2})
|
||||
self.assertEqual(cf[self.default_section]['a'], '5.2')
|
||||
self.assertAlmostEqual(cf[self.default_section].getfloat('a'), 5.2)
|
||||
|
||||
|
||||
class StrictTestCase(BasicTestCase, unittest.TestCase):
|
||||
config_class = configparser.RawConfigParser
|
||||
|
@ -959,6 +950,15 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase):
|
|||
cf = self.newconfig()
|
||||
self.assertRaises(ValueError, cf.add_section, self.default_section)
|
||||
|
||||
def test_defaults_keyword(self):
|
||||
"""bpo-23835 fix for ConfigParser"""
|
||||
cf = self.newconfig(defaults={1: 2.4})
|
||||
self.assertEqual(cf[self.default_section]['1'], '2.4')
|
||||
self.assertAlmostEqual(cf[self.default_section].getfloat('1'), 2.4)
|
||||
cf = self.newconfig(defaults={"A": 5.2})
|
||||
self.assertEqual(cf[self.default_section]['a'], '5.2')
|
||||
self.assertAlmostEqual(cf[self.default_section].getfloat('a'), 5.2)
|
||||
|
||||
|
||||
class ConfigParserTestCaseNoInterpolation(BasicTestCase, unittest.TestCase):
|
||||
config_class = configparser.ConfigParser
|
||||
|
@ -1099,6 +1099,15 @@ class RawConfigParserTestCase(BasicTestCase, unittest.TestCase):
|
|||
cf.set('non-string', 1, 1)
|
||||
self.assertEqual(cf.get('non-string', 1), 1)
|
||||
|
||||
def test_defaults_keyword(self):
|
||||
"""bpo-23835 legacy behavior for RawConfigParser"""
|
||||
with self.assertRaises(AttributeError) as ctx:
|
||||
self.newconfig(defaults={1: 2.4})
|
||||
err = ctx.exception
|
||||
self.assertEqual(str(err), "'int' object has no attribute 'lower'")
|
||||
cf = self.newconfig(defaults={"A": 5.2})
|
||||
self.assertAlmostEqual(cf[self.default_section]['a'], 5.2)
|
||||
|
||||
|
||||
class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
|
||||
delimiters = (':=', '$')
|
||||
|
|
Loading…
Reference in New Issue