Index: Lib/ConfigParser.py =================================================================== --- Lib/ConfigParser.py (revision 53450) +++ Lib/ConfigParser.py (working copy) @@ -588,6 +588,10 @@ class SafeConfigParser(ConfigParser): + def __init__(self, defaults=None, dict_type=dict): + ConfigParser.__init__(self, defaults, dict_type) + self._value_pattern = re.compile(r"%[^%(]|%$") + def _interpolate(self, section, option, rawval, vars): # do the string interpolation L = [] @@ -638,4 +642,9 @@ """Set an option. Extend ConfigParser.set: check for string values.""" if not isinstance(value, basestring): raise TypeError("option values must be strings") - ConfigParser.set(self, section, option, value) + ConfigParser.set(self, section, option, self.validate_value(value)) + + def validate_value(self, value): + if self._value_pattern.search(value): + raise ValueError("invalid interpolation syntax: %s" % value) + return value Index: Lib/test/test_cfgparser.py =================================================================== --- Lib/test/test_cfgparser.py (revision 53450) +++ Lib/test/test_cfgparser.py (working copy) @@ -422,6 +422,18 @@ self.assertEqual(cf.get("section", "ok"), "xxx/%s") self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") + def test_set_malformatted_interpolation(self): + cf = self.fromstring("[sect]\n" + "option1=foo\n") + + self.assertEqual(cf.get('sect', "option1"), "foo") + + self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo") + self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%") + self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo") + + self.assertEqual(cf.get('sect', "option1"), "foo") + def test_set_nonstring_types(self): cf = self.fromstring("[sect]\n" "option1=foo\n")