configparser: fixed inconsistency where in SafeConfigParser option values
 were ensured to be strings but section names and option keys were not.
 Behaviour unchanged for RawConfigParser and ConfigParser.
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 @@
         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 @@
                     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 @@
             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 @@
         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 @@
     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 @@
         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 @@
         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 @@
 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 @@
                 "int": 42,
                 "float": 0.44,
                 "boolean": False,
+                123: "strange but acceptable",
             },
         }
         if self.allow_no_value:
@@ -716,6 +719,15 @@
                                 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 @@
         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 @@
         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()