SF bug #997050: Document, test, & check for non-string values in ConfigParser. Moved the new string-only restriction added in rev. 1.65 to the SafeConfigParser class, leaving existing ConfigParser & RawConfigParser behavior alone, and documented the conditions under which non-string values work.
This commit is contained in:
parent
68a1abdade
commit
1cbf206d32
|
@ -238,10 +238,12 @@ option in the given \var{section}.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{set}{section, option, value}
|
\begin{methoddesc}{set}{section, option, value}
|
||||||
If the given section exists, set the given option to the specified value;
|
If the given section exists, set the given option to the specified
|
||||||
otherwise raise \exception{NoSectionError}. \var{value} must be a
|
value; otherwise raise \exception{NoSectionError}. While it is
|
||||||
string (\class{str} or \class{unicode}); if not, \exception{TypeError}
|
possible to use \class{RawConfigParser} (or \class{ConfigParser} with
|
||||||
is raised.
|
\var{raw} parameters set to true) for \emph{internal} storage of
|
||||||
|
non-string values, full functionality (including interpolation and
|
||||||
|
output to files) can only be achieved using string values.
|
||||||
\versionadded{1.6}
|
\versionadded{1.6}
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
|
@ -281,8 +283,6 @@ option names case sensitive.
|
||||||
|
|
||||||
The \class{ConfigParser} class extends some methods of the
|
The \class{ConfigParser} class extends some methods of the
|
||||||
\class{RawConfigParser} interface, adding some optional arguments.
|
\class{RawConfigParser} interface, adding some optional arguments.
|
||||||
The \class{SafeConfigParser} class implements the same extended
|
|
||||||
interface.
|
|
||||||
|
|
||||||
\begin{methoddesc}{get}{section, option\optional{, raw\optional{, vars}}}
|
\begin{methoddesc}{get}{section, option\optional{, raw\optional{, vars}}}
|
||||||
Get an \var{option} value for the named \var{section}. All the
|
Get an \var{option} value for the named \var{section}. All the
|
||||||
|
@ -297,3 +297,17 @@ option in the given \var{section}. Optional arguments have the
|
||||||
same meaning as for the \method{get()} method.
|
same meaning as for the \method{get()} method.
|
||||||
\versionadded{2.3}
|
\versionadded{2.3}
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{SafeConfigParser Objects \label{SafeConfigParser-objects}}
|
||||||
|
|
||||||
|
The \class{SafeConfigParser} class implements the same extended
|
||||||
|
interface as \class{ConfigParser}, with the following addition:
|
||||||
|
|
||||||
|
\begin{methoddesc}{set}{section, option, value}
|
||||||
|
If the given section exists, set the given option to the specified
|
||||||
|
value; otherwise raise \exception{NoSectionError}. \var{value} must
|
||||||
|
be a string (\class{str} or \class{unicode}); if not,
|
||||||
|
\exception{TypeError} is raised.
|
||||||
|
\versionadded{2.4}
|
||||||
|
\end{methoddesc}
|
||||||
|
|
|
@ -92,7 +92,8 @@ import re
|
||||||
__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError",
|
__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError",
|
||||||
"InterpolationError", "InterpolationDepthError",
|
"InterpolationError", "InterpolationDepthError",
|
||||||
"InterpolationSyntaxError", "ParsingError",
|
"InterpolationSyntaxError", "ParsingError",
|
||||||
"MissingSectionHeaderError", "ConfigParser", "SafeConfigParser",
|
"MissingSectionHeaderError",
|
||||||
|
"ConfigParser", "SafeConfigParser", "RawConfigParser",
|
||||||
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
|
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
|
||||||
|
|
||||||
DEFAULTSECT = "DEFAULT"
|
DEFAULTSECT = "DEFAULT"
|
||||||
|
@ -348,8 +349,6 @@ class RawConfigParser:
|
||||||
|
|
||||||
def set(self, section, option, value):
|
def set(self, section, option, value):
|
||||||
"""Set an option."""
|
"""Set an option."""
|
||||||
if not isinstance(value, basestring):
|
|
||||||
raise TypeError("option values must be strings")
|
|
||||||
if not section or section == DEFAULTSECT:
|
if not section or section == DEFAULTSECT:
|
||||||
sectdict = self._defaults
|
sectdict = self._defaults
|
||||||
else:
|
else:
|
||||||
|
@ -633,3 +632,9 @@ class SafeConfigParser(ConfigParser):
|
||||||
raise InterpolationSyntaxError(
|
raise InterpolationSyntaxError(
|
||||||
option, section,
|
option, section,
|
||||||
"'%%' must be followed by '%%' or '(', found: %r" % (rest,))
|
"'%%' must be followed by '%%' or '(', found: %r" % (rest,))
|
||||||
|
|
||||||
|
def set(self, section, option, value):
|
||||||
|
"""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)
|
||||||
|
|
|
@ -240,18 +240,6 @@ class TestCaseBase(unittest.TestCase):
|
||||||
cf.set("sect", "option1", unicode("splat"))
|
cf.set("sect", "option1", unicode("splat"))
|
||||||
cf.set("sect", "option2", unicode("splat"))
|
cf.set("sect", "option2", unicode("splat"))
|
||||||
|
|
||||||
def test_set_nonstring_types(self):
|
|
||||||
cf = self.fromstring("[sect]\n"
|
|
||||||
"option1=foo\n")
|
|
||||||
# Check that we get a TypeError when setting non-string values
|
|
||||||
# in an existing section:
|
|
||||||
self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
|
|
||||||
self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
|
|
||||||
self.assertRaises(TypeError, cf.set, "sect", "option1", object())
|
|
||||||
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())
|
|
||||||
|
|
||||||
def test_read_returns_file_list(self):
|
def test_read_returns_file_list(self):
|
||||||
file1 = test_support.findfile("cfgparser.1")
|
file1 = test_support.findfile("cfgparser.1")
|
||||||
# check when we pass a mix of readable and non-readable files:
|
# check when we pass a mix of readable and non-readable files:
|
||||||
|
@ -344,6 +332,27 @@ class ConfigParserTestCase(TestCaseBase):
|
||||||
('key', '|value|'),
|
('key', '|value|'),
|
||||||
('name', 'value')])
|
('name', 'value')])
|
||||||
|
|
||||||
|
def test_set_nonstring_types(self):
|
||||||
|
cf = self.newconfig()
|
||||||
|
cf.add_section('non-string')
|
||||||
|
cf.set('non-string', 'int', 1)
|
||||||
|
cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
|
||||||
|
cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
|
||||||
|
'%(list)': '%(list)'})
|
||||||
|
cf.set('non-string', 'string_with_interpolation', '%(list)s')
|
||||||
|
self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
|
||||||
|
self.assertRaises(TypeError, cf.get, 'non-string', 'int')
|
||||||
|
self.assertEqual(cf.get('non-string', 'list', raw=True),
|
||||||
|
[0, 1, 1, 2, 3, 5, 8, 13, '%('])
|
||||||
|
self.assertRaises(TypeError, cf.get, 'non-string', 'list')
|
||||||
|
self.assertEqual(cf.get('non-string', 'dict', raw=True),
|
||||||
|
{'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
|
||||||
|
self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
|
||||||
|
self.assertEqual(cf.get('non-string', 'string_with_interpolation',
|
||||||
|
raw=True), '%(list)s')
|
||||||
|
self.assertRaises(ValueError, cf.get, 'non-string',
|
||||||
|
'string_with_interpolation', raw=False)
|
||||||
|
|
||||||
|
|
||||||
class RawConfigParserTestCase(TestCaseBase):
|
class RawConfigParserTestCase(TestCaseBase):
|
||||||
config_class = ConfigParser.RawConfigParser
|
config_class = ConfigParser.RawConfigParser
|
||||||
|
@ -368,6 +377,17 @@ class RawConfigParserTestCase(TestCaseBase):
|
||||||
('key', '|%(name)s|'),
|
('key', '|%(name)s|'),
|
||||||
('name', 'value')])
|
('name', 'value')])
|
||||||
|
|
||||||
|
def test_set_nonstring_types(self):
|
||||||
|
cf = self.newconfig()
|
||||||
|
cf.add_section('non-string')
|
||||||
|
cf.set('non-string', 'int', 1)
|
||||||
|
cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
|
||||||
|
cf.set('non-string', 'dict', {'pi': 3.14159})
|
||||||
|
self.assertEqual(cf.get('non-string', 'int'), 1)
|
||||||
|
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})
|
||||||
|
|
||||||
|
|
||||||
class SafeConfigParserTestCase(ConfigParserTestCase):
|
class SafeConfigParserTestCase(ConfigParserTestCase):
|
||||||
config_class = ConfigParser.SafeConfigParser
|
config_class = ConfigParser.SafeConfigParser
|
||||||
|
@ -382,6 +402,18 @@ class SafeConfigParserTestCase(ConfigParserTestCase):
|
||||||
self.assertEqual(cf.get("section", "ok"), "xxx/%s")
|
self.assertEqual(cf.get("section", "ok"), "xxx/%s")
|
||||||
self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
|
self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
|
||||||
|
|
||||||
|
def test_set_nonstring_types(self):
|
||||||
|
cf = self.fromstring("[sect]\n"
|
||||||
|
"option1=foo\n")
|
||||||
|
# Check that we get a TypeError when setting non-string values
|
||||||
|
# in an existing section:
|
||||||
|
self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
|
||||||
|
self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
|
||||||
|
self.assertRaises(TypeError, cf.set, "sect", "option1", object())
|
||||||
|
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())
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test_support.run_unittest(
|
test_support.run_unittest(
|
||||||
|
|
|
@ -99,6 +99,12 @@ Library
|
||||||
consistent with the handling of config file entries and runtime-set
|
consistent with the handling of config file entries and runtime-set
|
||||||
options.
|
options.
|
||||||
|
|
||||||
|
- SF bug #997050: Document, test, & check for non-string values in
|
||||||
|
ConfigParser. Moved the new string-only restriction added in
|
||||||
|
rev. 1.65 to the SafeConfigParser class, leaving existing
|
||||||
|
ConfigParser & RawConfigParser behavior alone, and documented the
|
||||||
|
conditions under which non-string values work.
|
||||||
|
|
||||||
Build
|
Build
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue