blob: 1ae720ecbb0a002a4dfc029f8c94fd2031890ec3 [file] [log] [blame]
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001import collections
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +00002import configparser
Guido van Rossum34d19282007-08-09 01:03:29 +00003import io
Brian Curtin9a27b0c2010-07-26 00:27:10 +00004import os
Fred Drakec6f28912002-10-25 19:40:49 +00005import unittest
Georg Brandl96a60ae2010-07-28 13:13:46 +00006import textwrap
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00007import warnings
Fred Drake8ef67672000-09-27 22:45:25 +00008
Benjamin Petersonee8712c2008-05-20 21:35:26 +00009from test import support
Fred Drake3d5f7e82000-12-04 16:30:40 +000010
Raymond Hettingerf80680d2008-02-06 00:07:11 +000011class SortedDict(collections.UserDict):
Fred Drake03c44a32010-02-19 06:08:41 +000012
Thomas Wouters89f507f2006-12-13 04:49:30 +000013 def items(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000014 return sorted(self.data.items())
Thomas Wouters89f507f2006-12-13 04:49:30 +000015
16 def keys(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000017 return sorted(self.data.keys())
Thomas Wouters9fe394c2007-02-05 01:24:16 +000018
Thomas Wouters89f507f2006-12-13 04:49:30 +000019 def values(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000020 return [i[1] for i in self.items()]
Thomas Wouters89f507f2006-12-13 04:49:30 +000021
22 def iteritems(self): return iter(self.items())
23 def iterkeys(self): return iter(self.keys())
24 __iter__ = iterkeys
25 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000026
Fred Drake03c44a32010-02-19 06:08:41 +000027
Georg Brandl96a60ae2010-07-28 13:13:46 +000028class CfgParserTestCaseClass(unittest.TestCase):
Fred Drake03c44a32010-02-19 06:08:41 +000029 allow_no_value = False
Georg Brandl96a60ae2010-07-28 13:13:46 +000030 delimiters = ('=', ':')
31 comment_prefixes = (';', '#')
32 empty_lines_in_values = True
33 dict_type = configparser._default_dict
Fred Drakea4923622010-08-09 12:52:45 +000034 strict = False
Łukasz Langac264c092010-11-20 16:15:37 +000035 default_section = configparser.DEFAULTSECT
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000036 interpolation = configparser._UNSET
Fred Drake03c44a32010-02-19 06:08:41 +000037
Fred Drakec6f28912002-10-25 19:40:49 +000038 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000039 arguments = dict(
Fred Drakea4923622010-08-09 12:52:45 +000040 defaults=defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000041 allow_no_value=self.allow_no_value,
42 delimiters=self.delimiters,
43 comment_prefixes=self.comment_prefixes,
44 empty_lines_in_values=self.empty_lines_in_values,
45 dict_type=self.dict_type,
Fred Drakea4923622010-08-09 12:52:45 +000046 strict=self.strict,
Łukasz Langac264c092010-11-20 16:15:37 +000047 default_section=self.default_section,
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000048 interpolation=self.interpolation,
Georg Brandl96a60ae2010-07-28 13:13:46 +000049 )
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000050 with warnings.catch_warnings():
51 warnings.simplefilter("ignore", category=DeprecationWarning)
52 instance = self.config_class(**arguments)
53 return instance
Fred Drake8ef67672000-09-27 22:45:25 +000054
Fred Drakec6f28912002-10-25 19:40:49 +000055 def fromstring(self, string, defaults=None):
56 cf = self.newconfig(defaults)
Fred Drakea4923622010-08-09 12:52:45 +000057 cf.read_string(string)
Fred Drakec6f28912002-10-25 19:40:49 +000058 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000059
Georg Brandl96a60ae2010-07-28 13:13:46 +000060class BasicTestCase(CfgParserTestCaseClass):
61
Fred Drakea4923622010-08-09 12:52:45 +000062 def basic_test(self, cf):
Georg Brandl96a60ae2010-07-28 13:13:46 +000063 E = ['Commented Bar',
64 'Foo Bar',
65 'Internationalized Stuff',
66 'Long Line',
67 'Section\\with$weird%characters[\t',
68 'Spaces',
69 'Spacey Bar',
70 'Spacey Bar From The Beginning',
Fred Drakecc645b92010-09-04 04:35:34 +000071 'Types',
Fred Drake03c44a32010-02-19 06:08:41 +000072 ]
Łukasz Langa26d513c2010-11-10 18:57:39 +000073
Fred Drake03c44a32010-02-19 06:08:41 +000074 if self.allow_no_value:
Fred Drakecc645b92010-09-04 04:35:34 +000075 E.append('NoValue')
Fred Drake03c44a32010-02-19 06:08:41 +000076 E.sort()
Łukasz Langa26d513c2010-11-10 18:57:39 +000077
78 # API access
79 L = cf.sections()
80 L.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000081 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000082 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000083
Łukasz Langa26d513c2010-11-10 18:57:39 +000084 # mapping access
85 L = [section for section in cf]
86 L.sort()
Łukasz Langac264c092010-11-20 16:15:37 +000087 E.append(self.default_section)
Łukasz Langa26d513c2010-11-10 18:57:39 +000088 E.sort()
89 eq(L, E)
90
Fred Drakec6f28912002-10-25 19:40:49 +000091 # The use of spaces in the section names serves as a
92 # regression test for SourceForge bug #583248:
93 # http://www.python.org/sf/583248
Łukasz Langa26d513c2010-11-10 18:57:39 +000094
95 # API access
96 eq(cf.get('Foo Bar', 'foo'), 'bar1')
97 eq(cf.get('Spacey Bar', 'foo'), 'bar2')
98 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
Georg Brandl96a60ae2010-07-28 13:13:46 +000099 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000100 eq(cf.get('Commented Bar', 'foo'), 'bar4')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000101 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +0000102 eq(cf.get('Spaces', 'key with spaces'), 'value')
103 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc645b92010-09-04 04:35:34 +0000104 eq(cf.getint('Types', 'int'), 42)
105 eq(cf.get('Types', 'int'), "42")
106 self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
107 eq(cf.get('Types', 'float'), "0.44")
108 eq(cf.getboolean('Types', 'boolean'), False)
Fred Drake03c44a32010-02-19 06:08:41 +0000109 if self.allow_no_value:
110 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000111
Łukasz Langa26d513c2010-11-10 18:57:39 +0000112 # test vars= and fallback=
113 eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
Fred Drakecc645b92010-09-04 04:35:34 +0000114 eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
115 with self.assertRaises(configparser.NoSectionError):
116 cf.get('No Such Foo Bar', 'foo')
117 with self.assertRaises(configparser.NoOptionError):
118 cf.get('Foo Bar', 'no-such-foo')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000119 eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
120 eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
121 eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
122 eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
123 eq(cf.getint('Types', 'int', fallback=18), 42)
124 eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
125 eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
Fred Drakecc645b92010-09-04 04:35:34 +0000126 self.assertAlmostEqual(cf.getfloat('Types', 'float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000127 fallback=0.0), 0.44)
Fred Drakecc645b92010-09-04 04:35:34 +0000128 self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000129 fallback=0.0), 0.0)
130 eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
131 eq(cf.getboolean('Types', 'boolean', fallback=True), False)
132 eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
Fred Drakecc645b92010-09-04 04:35:34 +0000133 "yes") # sic!
Łukasz Langa26d513c2010-11-10 18:57:39 +0000134 eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
135 eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
Fred Drakecc645b92010-09-04 04:35:34 +0000136 if self.allow_no_value:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000137 eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
Fred Drakecc645b92010-09-04 04:35:34 +0000138 eq(cf.get('NoValue', 'no-such-option-without-value',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000139 fallback=False), False)
Fred Drakecc645b92010-09-04 04:35:34 +0000140
Łukasz Langa26d513c2010-11-10 18:57:39 +0000141 # mapping access
142 eq(cf['Foo Bar']['foo'], 'bar1')
143 eq(cf['Spacey Bar']['foo'], 'bar2')
Łukasz Langaa73dc9d2010-11-21 13:56:42 +0000144 section = cf['Spacey Bar From The Beginning']
145 eq(section.name, 'Spacey Bar From The Beginning')
146 self.assertIs(section.parser, cf)
147 with self.assertRaises(AttributeError):
148 section.name = 'Name is read-only'
149 with self.assertRaises(AttributeError):
150 section.parser = 'Parser is read-only'
151 eq(section['foo'], 'bar3')
152 eq(section['baz'], 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000153 eq(cf['Commented Bar']['foo'], 'bar4')
154 eq(cf['Commented Bar']['baz'], 'qwe')
155 eq(cf['Spaces']['key with spaces'], 'value')
156 eq(cf['Spaces']['another with spaces'], 'splat!')
157 eq(cf['Long Line']['foo'],
158 'this line is much, much longer than my editor\nlikes it.')
159 if self.allow_no_value:
160 eq(cf['NoValue']['option-without-value'], None)
161
Fred Drakec6f28912002-10-25 19:40:49 +0000162 # Make sure the right things happen for remove_option();
163 # added to include check for SourceForge bug #123324:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000164
165 # API acceess
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000166 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000167 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000168 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000169 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000170 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000171 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000172 " that was removed")
173
Michael Foordbd6c0792010-07-25 23:09:25 +0000174 with self.assertRaises(configparser.NoSectionError) as cm:
175 cf.remove_option('No Such Section', 'foo')
176 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000177
178 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000179 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000180
Łukasz Langa26d513c2010-11-10 18:57:39 +0000181 # mapping access
182 del cf['Spacey Bar']['foo']
183 self.assertFalse('foo' in cf['Spacey Bar'])
184 with self.assertRaises(KeyError):
185 del cf['Spacey Bar']['foo']
186 with self.assertRaises(KeyError):
187 del cf['No Such Section']['foo']
188
Fred Drakea4923622010-08-09 12:52:45 +0000189 def test_basic(self):
190 config_string = """\
191[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000192foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000193[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000194foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000195[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000196 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000197 baz {0[0]} qwe
198[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000199foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000200baz{0[0]}qwe {1[0]}another one
201[Long Line]
202foo{0[1]} this line is much, much longer than my editor
203 likes it.
204[Section\\with$weird%characters[\t]
205[Internationalized Stuff]
206foo[bg]{0[1]} Bulgarian
207foo{0[0]}Default
208foo[en]{0[0]}English
209foo[de]{0[0]}Deutsch
210[Spaces]
211key with spaces {0[1]} value
212another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000213[Types]
214int {0[1]} 42
215float {0[0]} 0.44
216boolean {0[0]} NO
Fred Drakea4923622010-08-09 12:52:45 +0000217""".format(self.delimiters, self.comment_prefixes)
218 if self.allow_no_value:
219 config_string += (
220 "[NoValue]\n"
221 "option-without-value\n"
222 )
223 cf = self.fromstring(config_string)
224 self.basic_test(cf)
225 if self.strict:
226 with self.assertRaises(configparser.DuplicateOptionError):
227 cf.read_string(textwrap.dedent("""\
228 [Duplicate Options Here]
229 option {0[0]} with a value
230 option {0[1]} with another value
231 """.format(self.delimiters)))
232 with self.assertRaises(configparser.DuplicateSectionError):
233 cf.read_string(textwrap.dedent("""\
234 [And Now For Something]
235 completely different {0[0]} True
236 [And Now For Something]
237 the larch {0[1]} 1
238 """.format(self.delimiters)))
239 else:
240 cf.read_string(textwrap.dedent("""\
241 [Duplicate Options Here]
242 option {0[0]} with a value
243 option {0[1]} with another value
244 """.format(self.delimiters)))
245
246 cf.read_string(textwrap.dedent("""\
247 [And Now For Something]
248 completely different {0[0]} True
249 [And Now For Something]
250 the larch {0[1]} 1
251 """.format(self.delimiters)))
252
253 def test_basic_from_dict(self):
254 config = {
255 "Foo Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000256 "foo": "bar1",
Fred Drakea4923622010-08-09 12:52:45 +0000257 },
258 "Spacey Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000259 "foo": "bar2",
Fred Drakea4923622010-08-09 12:52:45 +0000260 },
261 "Spacey Bar From The Beginning": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000262 "foo": "bar3",
Fred Drakea4923622010-08-09 12:52:45 +0000263 "baz": "qwe",
264 },
265 "Commented Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000266 "foo": "bar4",
Fred Drakea4923622010-08-09 12:52:45 +0000267 "baz": "qwe",
268 },
269 "Long Line": {
270 "foo": "this line is much, much longer than my editor\nlikes "
271 "it.",
272 },
273 "Section\\with$weird%characters[\t": {
274 },
275 "Internationalized Stuff": {
276 "foo[bg]": "Bulgarian",
277 "foo": "Default",
278 "foo[en]": "English",
279 "foo[de]": "Deutsch",
280 },
281 "Spaces": {
282 "key with spaces": "value",
283 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000284 },
285 "Types": {
286 "int": 42,
287 "float": 0.44,
288 "boolean": False,
289 },
Fred Drakea4923622010-08-09 12:52:45 +0000290 }
291 if self.allow_no_value:
292 config.update({
293 "NoValue": {
294 "option-without-value": None,
295 }
296 })
297 cf = self.newconfig()
298 cf.read_dict(config)
299 self.basic_test(cf)
300 if self.strict:
301 with self.assertRaises(configparser.DuplicateOptionError):
302 cf.read_dict({
303 "Duplicate Options Here": {
304 'option': 'with a value',
305 'OPTION': 'with another value',
306 },
307 })
308 else:
309 cf.read_dict({
310 "Duplicate Options Here": {
311 'option': 'with a value',
312 'OPTION': 'with another value',
313 },
314 })
315
316
Fred Drakec6f28912002-10-25 19:40:49 +0000317 def test_case_sensitivity(self):
318 cf = self.newconfig()
319 cf.add_section("A")
320 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000321 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000322 L = cf.sections()
323 L.sort()
324 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000325 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000326 cf.set("a", "B", "value")
327 eq(cf.options("a"), ["b"])
328 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000329 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000330 with self.assertRaises(configparser.NoSectionError):
331 # section names are case-sensitive
332 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000333 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000334 cf.set("A", "A-B", "A-B value")
335 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000336 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000337 cf.has_option("A", opt),
338 "has_option() returned false for option which should exist")
339 eq(cf.options("A"), ["a-b"])
340 eq(cf.options("a"), ["b"])
341 cf.remove_option("a", "B")
342 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000343
Fred Drakec6f28912002-10-25 19:40:49 +0000344 # SF bug #432369:
345 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000346 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000347 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000348 eq(cf.options("MySection"), ["option"])
349 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000350
Fred Drakec6f28912002-10-25 19:40:49 +0000351 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000352 cf = self.fromstring("[section]\n"
353 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000354 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000355 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000356
Fred Drake3c823aa2001-02-26 21:55:34 +0000357
Łukasz Langa26d513c2010-11-10 18:57:39 +0000358 def test_case_sensitivity_mapping_access(self):
359 cf = self.newconfig()
360 cf["A"] = {}
361 cf["a"] = {"B": "value"}
362 cf["B"] = {}
363 L = [section for section in cf]
364 L.sort()
365 eq = self.assertEqual
Ezio Melotti263cbdf2010-11-29 02:02:10 +0000366 elem_eq = self.assertCountEqual
Łukasz Langac264c092010-11-20 16:15:37 +0000367 eq(L, sorted(["A", "B", self.default_section, "a"]))
Łukasz Langa26d513c2010-11-10 18:57:39 +0000368 eq(cf["a"].keys(), {"b"})
369 eq(cf["a"]["b"], "value",
370 "could not locate option, expecting case-insensitive option names")
371 with self.assertRaises(KeyError):
372 # section names are case-sensitive
373 cf["b"]["A"] = "value"
374 self.assertTrue("b" in cf["a"])
375 cf["A"]["A-B"] = "A-B value"
376 for opt in ("a-b", "A-b", "a-B", "A-B"):
377 self.assertTrue(
378 opt in cf["A"],
379 "has_option() returned false for option which should exist")
380 eq(cf["A"].keys(), {"a-b"})
381 eq(cf["a"].keys(), {"b"})
382 del cf["a"]["B"]
383 elem_eq(cf["a"].keys(), {})
384
385 # SF bug #432369:
386 cf = self.fromstring(
387 "[MySection]\nOption{} first line \n\tsecond line \n".format(
388 self.delimiters[0]))
389 eq(cf["MySection"].keys(), {"option"})
390 eq(cf["MySection"]["Option"], "first line\nsecond line")
391
392 # SF bug #561822:
393 cf = self.fromstring("[section]\n"
394 "nekey{}nevalue\n".format(self.delimiters[0]),
395 defaults={"key":"value"})
396 self.assertTrue("Key" in cf["section"])
397
David Goodger68a1abd2004-10-03 15:40:25 +0000398 def test_default_case_sensitivity(self):
399 cf = self.newconfig({"foo": "Bar"})
400 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000401 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000402 "could not locate option, expecting case-insensitive option names")
403 cf = self.newconfig({"Foo": "Bar"})
404 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000405 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000406 "could not locate option, expecting case-insensitive defaults")
407
Fred Drakec6f28912002-10-25 19:40:49 +0000408 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000409 cf = self.newconfig()
410 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000411 "[Foo]\n"
412 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000413 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000414 "[Foo]\n"
415 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000416 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000417 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000418 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000419 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000420 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000421 "[Foo]\n wrong-indent\n")
422 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000423 # read_file on a real file
424 tricky = support.findfile("cfgparser.3")
425 if self.delimiters[0] == '=':
426 error = configparser.ParsingError
427 expected = (tricky,)
428 else:
429 error = configparser.MissingSectionHeaderError
430 expected = (tricky, 1,
431 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000432 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000433 e = self.parse_error(cf, error, f)
434 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000435
Fred Drakea4923622010-08-09 12:52:45 +0000436 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000437 if hasattr(src, 'readline'):
438 sio = src
439 else:
440 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000441 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000442 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000443 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000444
Fred Drakec6f28912002-10-25 19:40:49 +0000445 def test_query_errors(self):
446 cf = self.newconfig()
447 self.assertEqual(cf.sections(), [],
448 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000449 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000450 "new ConfigParser should have no acknowledged "
451 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000452 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000453 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000454 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000455 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000456 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000457 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000458 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000459 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000460 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000461
Fred Drakea4923622010-08-09 12:52:45 +0000462 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000463 try:
Fred Drakea4923622010-08-09 12:52:45 +0000464 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000465 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000466 return e
467 else:
468 self.fail("expected exception type %s.%s"
469 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000470
Fred Drakec6f28912002-10-25 19:40:49 +0000471 def test_boolean(self):
472 cf = self.fromstring(
473 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000474 "T1{equals}1\n"
475 "T2{equals}TRUE\n"
476 "T3{equals}True\n"
477 "T4{equals}oN\n"
478 "T5{equals}yes\n"
479 "F1{equals}0\n"
480 "F2{equals}FALSE\n"
481 "F3{equals}False\n"
482 "F4{equals}oFF\n"
483 "F5{equals}nO\n"
484 "E1{equals}2\n"
485 "E2{equals}foo\n"
486 "E3{equals}-1\n"
487 "E4{equals}0.1\n"
488 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000489 )
490 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000491 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
492 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000493 self.assertRaises(ValueError,
494 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000495
Fred Drakec6f28912002-10-25 19:40:49 +0000496 def test_weird_errors(self):
497 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000498 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000499 with self.assertRaises(configparser.DuplicateSectionError) as cm:
500 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000501 e = cm.exception
502 self.assertEqual(str(e), "Section 'Foo' already exists")
503 self.assertEqual(e.args, ("Foo", None, None))
504
505 if self.strict:
506 with self.assertRaises(configparser.DuplicateSectionError) as cm:
507 cf.read_string(textwrap.dedent("""\
508 [Foo]
509 will this be added{equals}True
510 [Bar]
511 what about this{equals}True
512 [Foo]
513 oops{equals}this won't
514 """.format(equals=self.delimiters[0])), source='<foo-bar>')
515 e = cm.exception
516 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
517 "section 'Foo' already exists")
518 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
519
520 with self.assertRaises(configparser.DuplicateOptionError) as cm:
521 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
522 e = cm.exception
523 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
524 "in section 'Bar' already exists")
525 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000526
527 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000528 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000529 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000530 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000531 " likes it.\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000532 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000533 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000534 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000535 "[Long Line - With Comments!]\n"
536 "test {0[1]} we {comment} can\n"
537 " also {comment} place\n"
538 " comments {comment} in\n"
539 " multiline {comment} values"
Łukasz Langac264c092010-11-20 16:15:37 +0000540 "\n".format(self.delimiters, comment=self.comment_prefixes[0],
541 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000542 )
Fred Drake03c44a32010-02-19 06:08:41 +0000543 if self.allow_no_value:
544 config_string += (
545 "[Valueless]\n"
546 "option-without-value\n"
547 )
548
549 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000550 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000551 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000552 expect_string = (
Łukasz Langac264c092010-11-20 16:15:37 +0000553 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000554 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000555 "\tlong line\n"
556 "\n"
557 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000558 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000559 "\tlikes it.\n"
560 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000561 "[Long Line - With Comments!]\n"
562 "test {equals} we\n"
563 "\talso\n"
564 "\tcomments\n"
565 "\tmultiline\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000566 "\n".format(equals=self.delimiters[0],
567 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000568 )
Fred Drake03c44a32010-02-19 06:08:41 +0000569 if self.allow_no_value:
570 expect_string += (
571 "[Valueless]\n"
572 "option-without-value\n"
573 "\n"
574 )
575 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000576
Fred Drakeabc086f2004-05-18 03:29:52 +0000577 def test_set_string_types(self):
578 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000579 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000580 # Check that we don't get an exception when setting values in
581 # an existing section using strings:
582 class mystr(str):
583 pass
584 cf.set("sect", "option1", "splat")
585 cf.set("sect", "option1", mystr("splat"))
586 cf.set("sect", "option2", "splat")
587 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000588 cf.set("sect", "option1", "splat")
589 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000590
Fred Drake82903142004-05-18 04:24:02 +0000591 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000592 if self.delimiters[0] != '=':
593 # skip reading the file if we're using an incompatible format
594 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000595 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000596 # check when we pass a mix of readable and non-readable files:
597 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000598 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000599 self.assertEqual(parsed_files, [file1])
600 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
601 # check when we pass only a filename:
602 cf = self.newconfig()
603 parsed_files = cf.read(file1)
604 self.assertEqual(parsed_files, [file1])
605 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
606 # check when we pass only missing files:
607 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000608 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000609 self.assertEqual(parsed_files, [])
610 # check when we pass no files:
611 cf = self.newconfig()
612 parsed_files = cf.read([])
613 self.assertEqual(parsed_files, [])
614
Fred Drakec6f28912002-10-25 19:40:49 +0000615 # shared by subclasses
616 def get_interpolation_config(self):
617 return self.fromstring(
618 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000619 "bar{equals}something %(with1)s interpolation (1 step)\n"
620 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
621 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
622 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
623 "with11{equals}%(with10)s\n"
624 "with10{equals}%(with9)s\n"
625 "with9{equals}%(with8)s\n"
626 "with8{equals}%(With7)s\n"
627 "with7{equals}%(WITH6)s\n"
628 "with6{equals}%(with5)s\n"
629 "With5{equals}%(with4)s\n"
630 "WITH4{equals}%(with3)s\n"
631 "with3{equals}%(with2)s\n"
632 "with2{equals}%(with1)s\n"
633 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000634 "\n"
635 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000636 "foo{equals}%(bar)s\n"
637 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000638 "\n"
639 "[Interpolation Error]\n"
Fred Drake54782192002-12-31 06:57:25 +0000640 # no definition for 'reference'
Łukasz Langa5c863392010-11-21 13:41:35 +0000641 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
Fred Drake95b96d32001-02-12 17:23:20 +0000642
Fred Drake98e3b292002-10-25 20:42:44 +0000643 def check_items_config(self, expected):
644 cf = self.fromstring(
645 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000646 "name {0[0]} value\n"
647 "key{0[1]} |%(name)s| \n"
Łukasz Langa5c863392010-11-21 13:41:35 +0000648 "getdefault{0[1]} |%(default)s|\n".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000649 defaults={"default": "<default>"})
650 L = list(cf.items("section"))
651 L.sort()
652 self.assertEqual(L, expected)
653
Fred Drake8ef67672000-09-27 22:45:25 +0000654
Fred Drakea4923622010-08-09 12:52:45 +0000655class StrictTestCase(BasicTestCase):
656 config_class = configparser.RawConfigParser
657 strict = True
658
659
Georg Brandl96a60ae2010-07-28 13:13:46 +0000660class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000661 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000662
663 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000664 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000665 configparser.ConfigParser: ("something %(with11)s "
666 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000667 configparser.SafeConfigParser: "%(with1)s",
668 }
Fred Drakec6f28912002-10-25 19:40:49 +0000669 cf = self.get_interpolation_config()
670 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000671 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
672 eq(cf.get("Foo", "bar9"),
673 "something with lots of interpolation (9 steps)")
674 eq(cf.get("Foo", "bar10"),
675 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000676 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000677 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000678
Fred Drake54782192002-12-31 06:57:25 +0000679 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000680 rawval = {
681 configparser.ConfigParser: '%(reference)s',
682 configparser.SafeConfigParser: '',
683 }
Fred Drakea4923622010-08-09 12:52:45 +0000684 cf = self.get_interpolation_config()
685 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000686 "Interpolation Error", "name")
687 self.assertEqual(e.reference, "reference")
688 self.assertEqual(e.section, "Interpolation Error")
689 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000690 self.assertEqual(e.args, ('name', 'Interpolation Error',
691 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000692
Fred Drake98e3b292002-10-25 20:42:44 +0000693 def test_items(self):
694 self.check_items_config([('default', '<default>'),
695 ('getdefault', '|<default>|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000696 ('key', '|value|'),
697 ('name', 'value')])
698
David Goodger1cbf2062004-10-03 15:55:09 +0000699 def test_set_nonstring_types(self):
700 cf = self.newconfig()
701 cf.add_section('non-string')
702 cf.set('non-string', 'int', 1)
703 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
704 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
705 '%(list)': '%(list)'})
706 cf.set('non-string', 'string_with_interpolation', '%(list)s')
707 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
708 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
709 self.assertEqual(cf.get('non-string', 'list', raw=True),
710 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
711 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
712 self.assertEqual(cf.get('non-string', 'dict', raw=True),
713 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
714 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
715 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
716 raw=True), '%(list)s')
717 self.assertRaises(ValueError, cf.get, 'non-string',
718 'string_with_interpolation', raw=False)
719
Georg Brandl96a60ae2010-07-28 13:13:46 +0000720class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
721 delimiters = (':=', '$')
722 comment_prefixes = ('//', '"')
723
Łukasz Langac264c092010-11-20 16:15:37 +0000724class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
725 default_section = 'general'
726
Georg Brandl96a60ae2010-07-28 13:13:46 +0000727class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000728 config_class = configparser.ConfigParser
729 wonderful_spam = ("I'm having spam spam spam spam "
730 "spam spam spam beaked beans spam "
731 "spam spam and spam!").replace(' ', '\t\n')
732
733 def setUp(self):
734 cf = self.newconfig()
735 for i in range(100):
736 s = 'section{}'.format(i)
737 cf.add_section(s)
738 for j in range(10):
739 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
740 with open(support.TESTFN, 'w') as f:
741 cf.write(f)
742
743 def tearDown(self):
744 os.unlink(support.TESTFN)
745
746 def test_dominating_multiline_values(self):
747 # We're reading from file because this is where the code changed
748 # during performance updates in Python 3.2
749 cf_from_file = self.newconfig()
750 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000751 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000752 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
753 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000754
Georg Brandl96a60ae2010-07-28 13:13:46 +0000755class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000756 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000757
758 def test_interpolation(self):
759 cf = self.get_interpolation_config()
760 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000761 eq(cf.get("Foo", "bar"),
762 "something %(with1)s interpolation (1 step)")
763 eq(cf.get("Foo", "bar9"),
764 "something %(with9)s lots of interpolation (9 steps)")
765 eq(cf.get("Foo", "bar10"),
766 "something %(with10)s lots of interpolation (10 steps)")
767 eq(cf.get("Foo", "bar11"),
768 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000769
Fred Drake98e3b292002-10-25 20:42:44 +0000770 def test_items(self):
771 self.check_items_config([('default', '<default>'),
772 ('getdefault', '|%(default)s|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000773 ('key', '|%(name)s|'),
774 ('name', 'value')])
775
David Goodger1cbf2062004-10-03 15:55:09 +0000776 def test_set_nonstring_types(self):
777 cf = self.newconfig()
778 cf.add_section('non-string')
779 cf.set('non-string', 'int', 1)
780 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
781 cf.set('non-string', 'dict', {'pi': 3.14159})
782 self.assertEqual(cf.get('non-string', 'int'), 1)
783 self.assertEqual(cf.get('non-string', 'list'),
784 [0, 1, 1, 2, 3, 5, 8, 13])
785 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000786
Georg Brandl96a60ae2010-07-28 13:13:46 +0000787class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
788 delimiters = (':=', '$')
789 comment_prefixes = ('//', '"')
790
791class RawConfigParserTestSambaConf(BasicTestCase):
792 config_class = configparser.RawConfigParser
793 comment_prefixes = ('#', ';', '//', '----')
794 empty_lines_in_values = False
795
796 def test_reading(self):
797 smbconf = support.findfile("cfgparser.2")
798 # check when we pass a mix of readable and non-readable files:
799 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000800 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000801 self.assertEqual(parsed_files, [smbconf])
802 sections = ['global', 'homes', 'printers',
803 'print$', 'pdf-generator', 'tmp', 'Agustin']
804 self.assertEqual(cf.sections(), sections)
805 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
806 self.assertEqual(cf.getint("global", "max log size"), 50)
807 self.assertEqual(cf.get("global", "hosts allow"), "127.")
808 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000809
Fred Drake0eebd5c2002-10-25 21:52:00 +0000810class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000811 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000812
813 def test_safe_interpolation(self):
814 # See http://www.python.org/sf/511737
815 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000816 "option1{eq}xxx\n"
817 "option2{eq}%(option1)s/xxx\n"
818 "ok{eq}%(option1)s/%%s\n"
819 "not_ok{eq}%(option2)s/%%s".format(
820 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000821 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
822 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
823
Guido van Rossumd8faa362007-04-27 19:54:29 +0000824 def test_set_malformatted_interpolation(self):
825 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000826 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000827
828 self.assertEqual(cf.get('sect', "option1"), "foo")
829
830 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
831 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
832 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
833
834 self.assertEqual(cf.get('sect', "option1"), "foo")
835
Georg Brandl1f9fa312009-04-27 16:42:58 +0000836 # bug #5741: double percents are *not* malformed
837 cf.set("sect", "option2", "foo%%bar")
838 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
839
David Goodger1cbf2062004-10-03 15:55:09 +0000840 def test_set_nonstring_types(self):
841 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000842 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000843 # Check that we get a TypeError when setting non-string values
844 # in an existing section:
845 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
846 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
847 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
848 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
849 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
850 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
851
Łukasz Langac264c092010-11-20 16:15:37 +0000852 def test_add_section_default(self):
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000853 cf = self.newconfig()
Łukasz Langac264c092010-11-20 16:15:37 +0000854 self.assertRaises(ValueError, cf.add_section, self.default_section)
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000855
Łukasz Langab6a6f5f2010-12-03 16:28:00 +0000856class SafeConfigParserTestCaseExtendedInterpolation(BasicTestCase):
857 config_class = configparser.SafeConfigParser
858 interpolation = configparser.ExtendedInterpolation()
859 default_section = 'common'
860
861 def test_extended_interpolation(self):
862 cf = self.fromstring(textwrap.dedent("""
863 [common]
864 favourite Beatle = Paul
865 favourite color = green
866
867 [tom]
868 favourite band = ${favourite color} day
869 favourite pope = John ${favourite Beatle} II
870 sequel = ${favourite pope}I
871
872 [ambv]
873 favourite Beatle = George
874 son of Edward VII = ${favourite Beatle} V
875 son of George V = ${son of Edward VII}I
876
877 [stanley]
878 favourite Beatle = ${ambv:favourite Beatle}
879 favourite pope = ${tom:favourite pope}
880 favourite color = black
881 favourite state of mind = paranoid
882 favourite movie = soylent ${common:favourite color}
883 favourite song = ${favourite color} sabbath - ${favourite state of mind}
884 """).strip())
885
886 eq = self.assertEqual
887 eq(cf['common']['favourite Beatle'], 'Paul')
888 eq(cf['common']['favourite color'], 'green')
889 eq(cf['tom']['favourite Beatle'], 'Paul')
890 eq(cf['tom']['favourite color'], 'green')
891 eq(cf['tom']['favourite band'], 'green day')
892 eq(cf['tom']['favourite pope'], 'John Paul II')
893 eq(cf['tom']['sequel'], 'John Paul III')
894 eq(cf['ambv']['favourite Beatle'], 'George')
895 eq(cf['ambv']['favourite color'], 'green')
896 eq(cf['ambv']['son of Edward VII'], 'George V')
897 eq(cf['ambv']['son of George V'], 'George VI')
898 eq(cf['stanley']['favourite Beatle'], 'George')
899 eq(cf['stanley']['favourite color'], 'black')
900 eq(cf['stanley']['favourite state of mind'], 'paranoid')
901 eq(cf['stanley']['favourite movie'], 'soylent green')
902 eq(cf['stanley']['favourite pope'], 'John Paul II')
903 eq(cf['stanley']['favourite song'],
904 'black sabbath - paranoid')
905
906 def test_endless_loop(self):
907 cf = self.fromstring(textwrap.dedent("""
908 [one for you]
909 ping = ${one for me:pong}
910
911 [one for me]
912 pong = ${one for you:ping}
913 """).strip())
914
915 with self.assertRaises(configparser.InterpolationDepthError):
916 cf['one for you']['ping']
917
918
919
Georg Brandl96a60ae2010-07-28 13:13:46 +0000920class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
921 delimiters = (':=', '$')
922 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000923
924class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
925 allow_no_value = True
926
Georg Brandl8dcaa732010-07-29 12:17:40 +0000927class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
928 config_class = configparser.SafeConfigParser
929 delimiters = {'='}
930 comment_prefixes = {'#'}
931 allow_no_value = True
932
933 def test_cfgparser_dot_3(self):
934 tricky = support.findfile("cfgparser.3")
935 cf = self.newconfig()
936 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
937 self.assertEqual(cf.sections(), ['strange',
938 'corruption',
939 'yeah, sections can be '
940 'indented as well',
941 'another one!',
942 'no values here',
943 'tricky interpolation',
944 'more interpolation'])
Łukasz Langac264c092010-11-20 16:15:37 +0000945 self.assertEqual(cf.getint(self.default_section, 'go',
Fred Drakecc645b92010-09-04 04:35:34 +0000946 vars={'interpolate': '-1'}), -1)
947 with self.assertRaises(ValueError):
948 # no interpolation will happen
Łukasz Langac264c092010-11-20 16:15:37 +0000949 cf.getint(self.default_section, 'go', raw=True,
950 vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000951 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
952 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
953 longname = 'yeah, sections can be indented as well'
954 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000955 self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000956 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
957 # `go` from DEFAULT
958 with self.assertRaises(configparser.InterpolationMissingOptionError):
959 cf.items('no values here')
960 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
961 self.assertEqual(cf.get('tricky interpolation', 'lets'),
962 cf.get('tricky interpolation', 'go'))
963 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
964
965 def test_unicode_failure(self):
966 tricky = support.findfile("cfgparser.3")
967 cf = self.newconfig()
968 with self.assertRaises(UnicodeDecodeError):
969 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000970
Fred Drake88444412010-09-03 04:22:36 +0000971
972class Issue7005TestCase(unittest.TestCase):
973 """Test output when None is set() as a value and allow_no_value == False.
974
975 http://bugs.python.org/issue7005
976
977 """
978
979 expected_output = "[section]\noption = None\n\n"
980
981 def prepare(self, config_class):
982 # This is the default, but that's the point.
Łukasz Langab6a6f5f2010-12-03 16:28:00 +0000983 with warnings.catch_warnings():
984 warnings.simplefilter("ignore", category=DeprecationWarning)
985 cp = config_class(allow_no_value=False)
Fred Drake88444412010-09-03 04:22:36 +0000986 cp.add_section("section")
987 cp.set("section", "option", None)
988 sio = io.StringIO()
989 cp.write(sio)
990 return sio.getvalue()
991
992 def test_none_as_value_stringified(self):
993 output = self.prepare(configparser.ConfigParser)
994 self.assertEqual(output, self.expected_output)
995
996 def test_none_as_value_stringified_raw(self):
997 output = self.prepare(configparser.RawConfigParser)
998 self.assertEqual(output, self.expected_output)
999
1000
Thomas Wouters89f507f2006-12-13 04:49:30 +00001001class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +00001002 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +00001003
1004 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +00001005 cf = self.fromstring("[b]\n"
1006 "o4=1\n"
1007 "o3=2\n"
1008 "o2=3\n"
1009 "o1=4\n"
1010 "[a]\n"
1011 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +00001012 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +00001013 cf.write(output)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001014 self.assertEqual(output.getvalue(),
1015 "[a]\n"
1016 "k = v\n\n"
1017 "[b]\n"
1018 "o1 = 4\n"
1019 "o2 = 3\n"
1020 "o3 = 2\n"
1021 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +00001022
Fred Drake03c44a32010-02-19 06:08:41 +00001023
Georg Brandl96a60ae2010-07-28 13:13:46 +00001024class CompatibleTestCase(CfgParserTestCaseClass):
1025 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +00001026 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +00001027
1028 def test_comment_handling(self):
1029 config_string = textwrap.dedent("""\
1030 [Commented Bar]
1031 baz=qwe ; a comment
1032 foo: bar # not a comment!
1033 # but this is a comment
1034 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +00001035 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +00001036 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +00001037 """)
1038 cf = self.fromstring(config_string)
1039 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
1040 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +00001041 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +00001042
1043
Fred Drakec6f28912002-10-25 19:40:49 +00001044def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001045 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +00001046 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001047 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001048 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001049 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001050 RawConfigParserTestCaseNonStandardDelimiters,
1051 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +00001052 SafeConfigParserTestCase,
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00001053 SafeConfigParserTestCaseExtendedInterpolation,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001054 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +00001055 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +00001056 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001057 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +00001058 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +00001059 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001060 CompatibleTestCase,
Łukasz Langac264c092010-11-20 16:15:37 +00001061 ConfigParserTestCaseNonStandardDefaultSection,
Fred Drake03c44a32010-02-19 06:08:41 +00001062 )
1063
Fred Drake3af0eb82002-10-25 18:09:24 +00001064
Fred Drakec6f28912002-10-25 19:40:49 +00001065if __name__ == "__main__":
1066 test_main()