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[, \
|
default_section=configparser.DEFAULTSECT[, \
|
||||||
interpolation])
|
interpolation])
|
||||||
|
|
||||||
Legacy variant of the :class:`ConfigParser` with interpolation disabled
|
Legacy variant of the :class:`ConfigParser`. It has interpolation
|
||||||
by default and unsafe ``add_section`` and ``set`` methods.
|
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::
|
.. note::
|
||||||
Consider using :class:`ConfigParser` instead which checks types of
|
Consider using :class:`ConfigParser` instead which checks types of
|
||||||
|
|
|
@ -635,7 +635,7 @@ class RawConfigParser(MutableMapping):
|
||||||
if converters is not _UNSET:
|
if converters is not _UNSET:
|
||||||
self._converters.update(converters)
|
self._converters.update(converters)
|
||||||
if defaults:
|
if defaults:
|
||||||
self.read_dict({default_section: defaults})
|
self._read_defaults(defaults)
|
||||||
|
|
||||||
def defaults(self):
|
def defaults(self):
|
||||||
return self._defaults
|
return self._defaults
|
||||||
|
@ -1121,6 +1121,12 @@ class RawConfigParser(MutableMapping):
|
||||||
section,
|
section,
|
||||||
name, val)
|
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):
|
def _handle_error(self, exc, fpname, lineno, line):
|
||||||
if not exc:
|
if not exc:
|
||||||
exc = ParsingError(fpname)
|
exc = ParsingError(fpname)
|
||||||
|
@ -1198,6 +1204,11 @@ class ConfigParser(RawConfigParser):
|
||||||
self._validate_value_types(section=section)
|
self._validate_value_types(section=section)
|
||||||
super().add_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):
|
class SafeConfigParser(ConfigParser):
|
||||||
"""ConfigParser alias for backwards compatibility purposes."""
|
"""ConfigParser alias for backwards compatibility purposes."""
|
||||||
|
|
|
@ -855,15 +855,6 @@ boolean {0[0]} NO
|
||||||
self.assertEqual(cf.get('DEFAULT', 'test'), 'test')
|
self.assertEqual(cf.get('DEFAULT', 'test'), 'test')
|
||||||
self.assertEqual(cf['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):
|
class StrictTestCase(BasicTestCase, unittest.TestCase):
|
||||||
config_class = configparser.RawConfigParser
|
config_class = configparser.RawConfigParser
|
||||||
|
@ -959,6 +950,15 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase):
|
||||||
cf = self.newconfig()
|
cf = self.newconfig()
|
||||||
self.assertRaises(ValueError, cf.add_section, self.default_section)
|
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):
|
class ConfigParserTestCaseNoInterpolation(BasicTestCase, unittest.TestCase):
|
||||||
config_class = configparser.ConfigParser
|
config_class = configparser.ConfigParser
|
||||||
|
@ -1099,6 +1099,15 @@ class RawConfigParserTestCase(BasicTestCase, unittest.TestCase):
|
||||||
cf.set('non-string', 1, 1)
|
cf.set('non-string', 1, 1)
|
||||||
self.assertEqual(cf.get('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):
|
class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
|
||||||
delimiters = (':=', '$')
|
delimiters = (':=', '$')
|
||||||
|
|
Loading…
Reference in New Issue