summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/configparser.py23
-rw-r--r--Lib/test/test_cfgparser.py23
2 files changed, 42 insertions, 4 deletions
diff --git a/Lib/configparser.py b/Lib/configparser.py
index eafcea3..e92d7fa 100644
--- a/Lib/configparser.py
+++ b/Lib/configparser.py
@@ -727,11 +727,15 @@ class RawConfigParser(MutableMapping):
that should be present in the section. If the used dictionary type
preserves order, sections and their keys will be added in order.
+ All types held in the dictionary are converted to strings during
+ reading, including section names, option names and keys.
+
Optional second argument is the `source' specifying the name of the
dictionary being read.
"""
elements_added = set()
for section, keys in dictionary.items():
+ section = str(section)
try:
self.add_section(section)
except (DuplicateSectionError, ValueError):
@@ -739,7 +743,7 @@ class RawConfigParser(MutableMapping):
raise
elements_added.add(section)
for key, value in keys.items():
- key = self.optionxform(key)
+ key = self.optionxform(str(key))
if value is not None:
value = str(value)
if self._strict and (section, key) in elements_added:
@@ -1128,7 +1132,7 @@ class RawConfigParser(MutableMapping):
raise ValueError('Not a boolean: %s' % value)
return self.BOOLEAN_STATES[value.lower()]
- def _validate_value_type(self, value):
+ def _validate_value_types(self, *, section="", option="", value=""):
"""Raises a TypeError for non-string values.
The only legal non-string value if we allow valueless
@@ -1141,6 +1145,10 @@ class RawConfigParser(MutableMapping):
for RawConfigParsers and ConfigParsers. It is invoked in every
case for mapping protocol access and in SafeConfigParser.set().
"""
+ if not isinstance(section, str):
+ raise TypeError("section names must be strings")
+ if not isinstance(option, str):
+ raise TypeError("option keys must be strings")
if not self._allow_no_value or value:
if not isinstance(value, str):
raise TypeError("option values must be strings")
@@ -1169,9 +1177,16 @@ class SafeConfigParser(ConfigParser):
def set(self, section, option, value=None):
"""Set an option. Extends RawConfigParser.set by validating type and
interpolation syntax on the value."""
- self._validate_value_type(value)
+ self._validate_value_types(option=option, value=value)
super().set(section, option, value)
+ def add_section(self, section):
+ """Create a new section in the configuration. Extends
+ RawConfigParser.add_section by validating if the section name is
+ a string."""
+ self._validate_value_types(section=section)
+ super().add_section(section)
+
class SectionProxy(MutableMapping):
"""A proxy for a single section from a parser."""
@@ -1196,7 +1211,7 @@ class SectionProxy(MutableMapping):
return self._parser.get(self._name, key)
def __setitem__(self, key, value):
- self._parser._validate_value_type(value)
+ self._parser._validate_value_types(option=key, value=value)
return self._parser.set(self._name, key, value)
def __delitem__(self, key):
diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py
index 1ae720e..24158ad 100644
--- a/Lib/test/test_cfgparser.py
+++ b/Lib/test/test_cfgparser.py
@@ -106,6 +106,7 @@ class BasicTestCase(CfgParserTestCaseClass):
self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
eq(cf.get('Types', 'float'), "0.44")
eq(cf.getboolean('Types', 'boolean'), False)
+ eq(cf.get('Types', '123'), 'strange but acceptable')
if self.allow_no_value:
eq(cf.get('NoValue', 'option-without-value'), None)
@@ -214,6 +215,7 @@ another with spaces {0[0]} splat!
int {0[1]} 42
float {0[0]} 0.44
boolean {0[0]} NO
+123 {0[1]} strange but acceptable
""".format(self.delimiters, self.comment_prefixes)
if self.allow_no_value:
config_string += (
@@ -286,6 +288,7 @@ boolean {0[0]} NO
"int": 42,
"float": 0.44,
"boolean": False,
+ 123: "strange but acceptable",
},
}
if self.allow_no_value:
@@ -716,6 +719,15 @@ class ConfigParserTestCase(BasicTestCase):
raw=True), '%(list)s')
self.assertRaises(ValueError, cf.get, 'non-string',
'string_with_interpolation', raw=False)
+ cf.add_section(123)
+ cf.set(123, 'this is sick', True)
+ self.assertEqual(cf.get(123, 'this is sick', raw=True), True)
+ with self.assertRaises(TypeError):
+ cf.get(123, 'this is sick')
+ cf.optionxform = lambda x: x
+ cf.set('non-string', 1, 1)
+ self.assertRaises(TypeError, cf.get, 'non-string', 1, 1)
+ self.assertEqual(cf.get('non-string', 1, raw=True), 1)
class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
delimiters = (':=', '$')
@@ -783,6 +795,15 @@ class RawConfigParserTestCase(BasicTestCase):
self.assertEqual(cf.get('non-string', 'list'),
[0, 1, 1, 2, 3, 5, 8, 13])
self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
+ cf.add_section(123)
+ cf.set(123, 'this is sick', True)
+ self.assertEqual(cf.get(123, 'this is sick'), True)
+ if cf._dict.__class__ is configparser._default_dict:
+ # would not work for SortedDict; only checking for the most common
+ # default dictionary (OrderedDict)
+ cf.optionxform = lambda x: x
+ cf.set('non-string', 1, 1)
+ self.assertEqual(cf.get('non-string', 1), 1)
class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
delimiters = (':=', '$')
@@ -848,6 +869,8 @@ class SafeConfigParserTestCase(ConfigParserTestCase):
self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
self.assertRaises(TypeError, cf.set, "sect", "option2", object())
+ self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
+ self.assertRaises(TypeError, cf.add_section, 123)
def test_add_section_default(self):
cf = self.newconfig()