6 from test
import test_support
8 class SortedDict(UserDict
.UserDict
):
10 result
= self
.data
.items()
15 result
= self
.data
.keys()
21 return [i
[1] for i
in values
]
23 def iteritems(self
): return iter(self
.items())
24 def iterkeys(self
): return iter(self
.keys())
26 def itervalues(self
): return iter(self
.values())
28 class TestCaseBase(unittest
.TestCase
):
29 def newconfig(self
, defaults
=None):
31 self
.cf
= self
.config_class()
33 self
.cf
= self
.config_class(defaults
)
36 def fromstring(self
, string
, defaults
=None):
37 cf
= self
.newconfig(defaults
)
38 sio
= StringIO
.StringIO(string
)
49 "foo: bar ; comment\n"
51 "foo: this line is much, much longer than my editor\n"
53 "[Section\\with$weird%characters[\t]\n"
54 "[Internationalized Stuff]\n"
55 "foo[bg]: Bulgarian\n"
60 "key with spaces : value\n"
61 "another with spaces = splat!\n"
66 eq(L
, [r
'Commented Bar',
68 r
'Internationalized Stuff',
70 r
'Section\with$weird%characters[' '\t',
75 # The use of spaces in the section names serves as a
76 # regression test for SourceForge bug #583248:
77 # http://www.python.org/sf/583248
78 eq(cf
.get('Foo Bar', 'foo'), 'bar')
79 eq(cf
.get('Spacey Bar', 'foo'), 'bar')
80 eq(cf
.get('Commented Bar', 'foo'), 'bar')
81 eq(cf
.get('Spaces', 'key with spaces'), 'value')
82 eq(cf
.get('Spaces', 'another with spaces'), 'splat!')
84 self
.assertFalse('__name__' in cf
.options("Foo Bar"),
85 '__name__ "option" should not be exposed by the API!')
87 # Make sure the right things happen for remove_option();
88 # added to include check for SourceForge bug #123324:
89 self
.assertTrue(cf
.remove_option('Foo Bar', 'foo'),
90 "remove_option() failed to report existence of option")
91 self
.assertFalse(cf
.has_option('Foo Bar', 'foo'),
92 "remove_option() failed to remove option")
93 self
.assertFalse(cf
.remove_option('Foo Bar', 'foo'),
94 "remove_option() failed to report non-existence of option"
97 self
.assertRaises(ConfigParser
.NoSectionError
,
98 cf
.remove_option
, 'No Such Section', 'foo')
100 eq(cf
.get('Long Line', 'foo'),
101 'this line is much, much longer than my editor\nlikes it.')
103 def test_case_sensitivity(self
):
104 cf
= self
.newconfig()
109 eq
= self
.assertEqual
111 cf
.set("a", "B", "value")
112 eq(cf
.options("a"), ["b"])
113 eq(cf
.get("a", "b"), "value",
114 "could not locate option, expecting case-insensitive option names")
115 self
.assertTrue(cf
.has_option("a", "b"))
116 cf
.set("A", "A-B", "A-B value")
117 for opt
in ("a-b", "A-b", "a-B", "A-B"):
119 cf
.has_option("A", opt
),
120 "has_option() returned false for option which should exist")
121 eq(cf
.options("A"), ["a-b"])
122 eq(cf
.options("a"), ["b"])
123 cf
.remove_option("a", "B")
124 eq(cf
.options("a"), [])
127 cf
= self
.fromstring(
128 "[MySection]\nOption: first line\n\tsecond line\n")
129 eq(cf
.options("MySection"), ["option"])
130 eq(cf
.get("MySection", "Option"), "first line\nsecond line")
133 cf
= self
.fromstring("[section]\nnekey=nevalue\n",
134 defaults
={"key":"value"})
135 self
.assertTrue(cf
.has_option("section", "Key"))
138 def test_default_case_sensitivity(self
):
139 cf
= self
.newconfig({"foo": "Bar"})
141 cf
.get("DEFAULT", "Foo"), "Bar",
142 "could not locate option, expecting case-insensitive option names")
143 cf
= self
.newconfig({"Foo": "Bar"})
145 cf
.get("DEFAULT", "Foo"), "Bar",
146 "could not locate option, expecting case-insensitive defaults")
148 def test_parse_errors(self
):
150 self
.parse_error(ConfigParser
.ParsingError
,
151 "[Foo]\n extra-spaces: splat\n")
152 self
.parse_error(ConfigParser
.ParsingError
,
153 "[Foo]\n extra-spaces= splat\n")
154 self
.parse_error(ConfigParser
.ParsingError
,
155 "[Foo]\noption-without-value\n")
156 self
.parse_error(ConfigParser
.ParsingError
,
157 "[Foo]\n:value-without-option-name\n")
158 self
.parse_error(ConfigParser
.ParsingError
,
159 "[Foo]\n=value-without-option-name\n")
160 self
.parse_error(ConfigParser
.MissingSectionHeaderError
,
163 def parse_error(self
, exc
, src
):
164 sio
= StringIO
.StringIO(src
)
165 self
.assertRaises(exc
, self
.cf
.readfp
, sio
)
167 def test_query_errors(self
):
168 cf
= self
.newconfig()
169 self
.assertEqual(cf
.sections(), [],
170 "new ConfigParser should have no defined sections")
171 self
.assertFalse(cf
.has_section("Foo"),
172 "new ConfigParser should have no acknowledged sections")
173 self
.assertRaises(ConfigParser
.NoSectionError
,
175 self
.assertRaises(ConfigParser
.NoSectionError
,
176 cf
.set, "foo", "bar", "value")
177 self
.get_error(ConfigParser
.NoSectionError
, "foo", "bar")
178 cf
.add_section("foo")
179 self
.get_error(ConfigParser
.NoOptionError
, "foo", "bar")
181 def get_error(self
, exc
, section
, option
):
183 self
.cf
.get(section
, option
)
187 self
.fail("expected exception type %s.%s"
188 % (exc
.__module
__, exc
.__name
__))
190 def test_boolean(self
):
191 cf
= self
.fromstring(
209 for x
in range(1, 5):
210 self
.assertTrue(cf
.getboolean('BOOLTEST', 't%d' % x
))
211 self
.assertFalse(cf
.getboolean('BOOLTEST', 'f%d' % x
))
212 self
.assertRaises(ValueError,
213 cf
.getboolean
, 'BOOLTEST', 'e%d' % x
)
215 def test_weird_errors(self
):
216 cf
= self
.newconfig()
217 cf
.add_section("Foo")
218 self
.assertRaises(ConfigParser
.DuplicateSectionError
,
219 cf
.add_section
, "Foo")
221 def test_write(self
):
222 cf
= self
.fromstring(
224 "foo: this line is much, much longer than my editor\n"
227 "foo: another very\n"
230 output
= StringIO
.StringIO()
235 "foo = another very\n"
239 "foo = this line is much, much longer than my editor\n"
244 def test_set_string_types(self
):
245 cf
= self
.fromstring("[sect]\n"
247 # Check that we don't get an exception when setting values in
248 # an existing section using strings:
251 cf
.set("sect", "option1", "splat")
252 cf
.set("sect", "option1", mystr("splat"))
253 cf
.set("sect", "option2", "splat")
254 cf
.set("sect", "option2", mystr("splat"))
260 cf
.set("sect", "option1", unicode("splat"))
261 cf
.set("sect", "option2", unicode("splat"))
263 def test_read_returns_file_list(self
):
264 file1
= test_support
.findfile("cfgparser.1")
265 # check when we pass a mix of readable and non-readable files:
266 cf
= self
.newconfig()
267 parsed_files
= cf
.read([file1
, "nonexistent-file"])
268 self
.assertEqual(parsed_files
, [file1
])
269 self
.assertEqual(cf
.get("Foo Bar", "foo"), "newbar")
270 # check when we pass only a filename:
271 cf
= self
.newconfig()
272 parsed_files
= cf
.read(file1
)
273 self
.assertEqual(parsed_files
, [file1
])
274 self
.assertEqual(cf
.get("Foo Bar", "foo"), "newbar")
275 # check when we pass only missing files:
276 cf
= self
.newconfig()
277 parsed_files
= cf
.read(["nonexistent-file"])
278 self
.assertEqual(parsed_files
, [])
279 # check when we pass no files:
280 cf
= self
.newconfig()
281 parsed_files
= cf
.read([])
282 self
.assertEqual(parsed_files
, [])
284 # shared by subclasses
285 def get_interpolation_config(self
):
286 return self
.fromstring(
288 "bar=something %(with1)s interpolation (1 step)\n"
289 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
290 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
291 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
292 "with11=%(with10)s\n"
304 "[Mutual Recursion]\n"
308 "[Interpolation Error]\n"
309 "name=%(reference)s\n",
310 # no definition for 'reference'
311 defaults
={"getname": "%(__name__)s"})
313 def check_items_config(self
, expected
):
314 cf
= self
.fromstring(
318 "getdefault: |%(default)s|\n"
319 "getname: |%(__name__)s|",
320 defaults
={"default": "<default>"})
321 L
= list(cf
.items("section"))
323 self
.assertEqual(L
, expected
)
326 class ConfigParserTestCase(TestCaseBase
):
327 config_class
= ConfigParser
.ConfigParser
329 def test_interpolation(self
):
330 cf
= self
.get_interpolation_config()
331 eq
= self
.assertEqual
332 eq(cf
.get("Foo", "getname"), "Foo")
333 eq(cf
.get("Foo", "bar"), "something with interpolation (1 step)")
334 eq(cf
.get("Foo", "bar9"),
335 "something with lots of interpolation (9 steps)")
336 eq(cf
.get("Foo", "bar10"),
337 "something with lots of interpolation (10 steps)")
338 self
.get_error(ConfigParser
.InterpolationDepthError
, "Foo", "bar11")
340 def test_interpolation_missing_value(self
):
341 cf
= self
.get_interpolation_config()
342 e
= self
.get_error(ConfigParser
.InterpolationError
,
343 "Interpolation Error", "name")
344 self
.assertEqual(e
.reference
, "reference")
345 self
.assertEqual(e
.section
, "Interpolation Error")
346 self
.assertEqual(e
.option
, "name")
348 def test_items(self
):
349 self
.check_items_config([('default', '<default>'),
350 ('getdefault', '|<default>|'),
351 ('getname', '|section|'),
355 def test_set_nonstring_types(self
):
356 cf
= self
.newconfig()
357 cf
.add_section('non-string')
358 cf
.set('non-string', 'int', 1)
359 cf
.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
360 cf
.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
361 '%(list)': '%(list)'})
362 cf
.set('non-string', 'string_with_interpolation', '%(list)s')
363 self
.assertEqual(cf
.get('non-string', 'int', raw
=True), 1)
364 self
.assertRaises(TypeError, cf
.get
, 'non-string', 'int')
365 self
.assertEqual(cf
.get('non-string', 'list', raw
=True),
366 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
367 self
.assertRaises(TypeError, cf
.get
, 'non-string', 'list')
368 self
.assertEqual(cf
.get('non-string', 'dict', raw
=True),
369 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
370 self
.assertRaises(TypeError, cf
.get
, 'non-string', 'dict')
371 self
.assertEqual(cf
.get('non-string', 'string_with_interpolation',
372 raw
=True), '%(list)s')
373 self
.assertRaises(ValueError, cf
.get
, 'non-string',
374 'string_with_interpolation', raw
=False)
377 class RawConfigParserTestCase(TestCaseBase
):
378 config_class
= ConfigParser
.RawConfigParser
380 def test_interpolation(self
):
381 cf
= self
.get_interpolation_config()
382 eq
= self
.assertEqual
383 eq(cf
.get("Foo", "getname"), "%(__name__)s")
384 eq(cf
.get("Foo", "bar"),
385 "something %(with1)s interpolation (1 step)")
386 eq(cf
.get("Foo", "bar9"),
387 "something %(with9)s lots of interpolation (9 steps)")
388 eq(cf
.get("Foo", "bar10"),
389 "something %(with10)s lots of interpolation (10 steps)")
390 eq(cf
.get("Foo", "bar11"),
391 "something %(with11)s lots of interpolation (11 steps)")
393 def test_items(self
):
394 self
.check_items_config([('default', '<default>'),
395 ('getdefault', '|%(default)s|'),
396 ('getname', '|%(__name__)s|'),
397 ('key', '|%(name)s|'),
400 def test_set_nonstring_types(self
):
401 cf
= self
.newconfig()
402 cf
.add_section('non-string')
403 cf
.set('non-string', 'int', 1)
404 cf
.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
405 cf
.set('non-string', 'dict', {'pi': 3.14159})
406 self
.assertEqual(cf
.get('non-string', 'int'), 1)
407 self
.assertEqual(cf
.get('non-string', 'list'),
408 [0, 1, 1, 2, 3, 5, 8, 13])
409 self
.assertEqual(cf
.get('non-string', 'dict'), {'pi': 3.14159})
412 class SafeConfigParserTestCase(ConfigParserTestCase
):
413 config_class
= ConfigParser
.SafeConfigParser
415 def test_safe_interpolation(self
):
416 # See http://www.python.org/sf/511737
417 cf
= self
.fromstring("[section]\n"
419 "option2=%(option1)s/xxx\n"
420 "ok=%(option1)s/%%s\n"
421 "not_ok=%(option2)s/%%s")
422 self
.assertEqual(cf
.get("section", "ok"), "xxx/%s")
423 self
.assertEqual(cf
.get("section", "not_ok"), "xxx/xxx/%s")
425 def test_set_malformatted_interpolation(self
):
426 cf
= self
.fromstring("[sect]\n"
429 self
.assertEqual(cf
.get('sect', "option1"), "foo")
431 self
.assertRaises(ValueError, cf
.set, "sect", "option1", "%foo")
432 self
.assertRaises(ValueError, cf
.set, "sect", "option1", "foo%")
433 self
.assertRaises(ValueError, cf
.set, "sect", "option1", "f%oo")
435 self
.assertEqual(cf
.get('sect', "option1"), "foo")
437 # bug #5741: double percents are *not* malformed
438 cf
.set("sect", "option2", "foo%%bar")
439 self
.assertEqual(cf
.get("sect", "option2"), "foo%bar")
441 def test_set_nonstring_types(self
):
442 cf
= self
.fromstring("[sect]\n"
444 # Check that we get a TypeError when setting non-string values
445 # in an existing section:
446 self
.assertRaises(TypeError, cf
.set, "sect", "option1", 1)
447 self
.assertRaises(TypeError, cf
.set, "sect", "option1", 1.0)
448 self
.assertRaises(TypeError, cf
.set, "sect", "option1", object())
449 self
.assertRaises(TypeError, cf
.set, "sect", "option2", 1)
450 self
.assertRaises(TypeError, cf
.set, "sect", "option2", 1.0)
451 self
.assertRaises(TypeError, cf
.set, "sect", "option2", object())
453 def test_add_section_default_1(self
):
454 cf
= self
.newconfig()
455 self
.assertRaises(ValueError, cf
.add_section
, "default")
457 def test_add_section_default_2(self
):
458 cf
= self
.newconfig()
459 self
.assertRaises(ValueError, cf
.add_section
, "DEFAULT")
461 class SortedTestCase(RawConfigParserTestCase
):
462 def newconfig(self
, defaults
=None):
463 self
.cf
= self
.config_class(defaults
=defaults
, dict_type
=SortedDict
)
466 def test_sorted(self
):
467 self
.fromstring("[b]\n"
474 output
= StringIO
.StringIO()
475 self
.cf
.write(output
)
476 self
.assertEquals(output
.getvalue(),
486 test_support
.run_unittest(
487 ConfigParserTestCase
,
488 RawConfigParserTestCase
,
489 SafeConfigParserTestCase
,
493 if __name__
== "__main__":