blob: 11aa2674e6fe12e1a07b5a3b22b17698ce89fd13 [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
Fred Drake8ef67672000-09-27 22:45:25 +00007
Benjamin Petersonee8712c2008-05-20 21:35:26 +00008from test import support
Fred Drake3d5f7e82000-12-04 16:30:40 +00009
Raymond Hettingerf80680d2008-02-06 00:07:11 +000010class SortedDict(collections.UserDict):
Fred Drake03c44a32010-02-19 06:08:41 +000011
Thomas Wouters89f507f2006-12-13 04:49:30 +000012 def items(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000013 return sorted(self.data.items())
Thomas Wouters89f507f2006-12-13 04:49:30 +000014
15 def keys(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000016 return sorted(self.data.keys())
Thomas Wouters9fe394c2007-02-05 01:24:16 +000017
Thomas Wouters89f507f2006-12-13 04:49:30 +000018 def values(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000019 return [i[1] for i in self.items()]
Thomas Wouters89f507f2006-12-13 04:49:30 +000020
21 def iteritems(self): return iter(self.items())
22 def iterkeys(self): return iter(self.keys())
23 __iter__ = iterkeys
24 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000025
Fred Drake03c44a32010-02-19 06:08:41 +000026
Georg Brandl96a60ae2010-07-28 13:13:46 +000027class CfgParserTestCaseClass(unittest.TestCase):
Fred Drake03c44a32010-02-19 06:08:41 +000028 allow_no_value = False
Georg Brandl96a60ae2010-07-28 13:13:46 +000029 delimiters = ('=', ':')
30 comment_prefixes = (';', '#')
31 empty_lines_in_values = True
32 dict_type = configparser._default_dict
Fred Drakea4923622010-08-09 12:52:45 +000033 strict = False
Fred Drake03c44a32010-02-19 06:08:41 +000034
Fred Drakec6f28912002-10-25 19:40:49 +000035 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000036 arguments = dict(
Fred Drakea4923622010-08-09 12:52:45 +000037 defaults=defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000038 allow_no_value=self.allow_no_value,
39 delimiters=self.delimiters,
40 comment_prefixes=self.comment_prefixes,
41 empty_lines_in_values=self.empty_lines_in_values,
42 dict_type=self.dict_type,
Fred Drakea4923622010-08-09 12:52:45 +000043 strict=self.strict,
Georg Brandl96a60ae2010-07-28 13:13:46 +000044 )
Fred Drakea4923622010-08-09 12:52:45 +000045 return self.config_class(**arguments)
Fred Drake8ef67672000-09-27 22:45:25 +000046
Fred Drakec6f28912002-10-25 19:40:49 +000047 def fromstring(self, string, defaults=None):
48 cf = self.newconfig(defaults)
Fred Drakea4923622010-08-09 12:52:45 +000049 cf.read_string(string)
Fred Drakec6f28912002-10-25 19:40:49 +000050 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000051
Georg Brandl96a60ae2010-07-28 13:13:46 +000052class BasicTestCase(CfgParserTestCaseClass):
53
Fred Drakea4923622010-08-09 12:52:45 +000054 def basic_test(self, cf):
Georg Brandl96a60ae2010-07-28 13:13:46 +000055 E = ['Commented Bar',
56 'Foo Bar',
57 'Internationalized Stuff',
58 'Long Line',
59 'Section\\with$weird%characters[\t',
60 'Spaces',
61 'Spacey Bar',
62 'Spacey Bar From The Beginning',
Fred Drakecc645b92010-09-04 04:35:34 +000063 'Types',
Fred Drake03c44a32010-02-19 06:08:41 +000064 ]
Łukasz Langa26d513c2010-11-10 18:57:39 +000065
Fred Drake03c44a32010-02-19 06:08:41 +000066 if self.allow_no_value:
Fred Drakecc645b92010-09-04 04:35:34 +000067 E.append('NoValue')
Fred Drake03c44a32010-02-19 06:08:41 +000068 E.sort()
Łukasz Langa26d513c2010-11-10 18:57:39 +000069
70 # API access
71 L = cf.sections()
72 L.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000073 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000074 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000075
Łukasz Langa26d513c2010-11-10 18:57:39 +000076 # mapping access
77 L = [section for section in cf]
78 L.sort()
79 E.append(configparser.DEFAULTSECT)
80 E.sort()
81 eq(L, E)
82
Fred Drakec6f28912002-10-25 19:40:49 +000083 # The use of spaces in the section names serves as a
84 # regression test for SourceForge bug #583248:
85 # http://www.python.org/sf/583248
Łukasz Langa26d513c2010-11-10 18:57:39 +000086
87 # API access
88 eq(cf.get('Foo Bar', 'foo'), 'bar1')
89 eq(cf.get('Spacey Bar', 'foo'), 'bar2')
90 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
Georg Brandl96a60ae2010-07-28 13:13:46 +000091 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +000092 eq(cf.get('Commented Bar', 'foo'), 'bar4')
Georg Brandl96a60ae2010-07-28 13:13:46 +000093 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +000094 eq(cf.get('Spaces', 'key with spaces'), 'value')
95 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc645b92010-09-04 04:35:34 +000096 eq(cf.getint('Types', 'int'), 42)
97 eq(cf.get('Types', 'int'), "42")
98 self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
99 eq(cf.get('Types', 'float'), "0.44")
100 eq(cf.getboolean('Types', 'boolean'), False)
Fred Drake03c44a32010-02-19 06:08:41 +0000101 if self.allow_no_value:
102 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000103
Łukasz Langa26d513c2010-11-10 18:57:39 +0000104 # test vars= and fallback=
105 eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
Fred Drakecc645b92010-09-04 04:35:34 +0000106 eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
107 with self.assertRaises(configparser.NoSectionError):
108 cf.get('No Such Foo Bar', 'foo')
109 with self.assertRaises(configparser.NoOptionError):
110 cf.get('Foo Bar', 'no-such-foo')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000111 eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
112 eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
113 eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
114 eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
115 eq(cf.getint('Types', 'int', fallback=18), 42)
116 eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
117 eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
Fred Drakecc645b92010-09-04 04:35:34 +0000118 self.assertAlmostEqual(cf.getfloat('Types', 'float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000119 fallback=0.0), 0.44)
Fred Drakecc645b92010-09-04 04:35:34 +0000120 self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000121 fallback=0.0), 0.0)
122 eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
123 eq(cf.getboolean('Types', 'boolean', fallback=True), False)
124 eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
Fred Drakecc645b92010-09-04 04:35:34 +0000125 "yes") # sic!
Łukasz Langa26d513c2010-11-10 18:57:39 +0000126 eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
127 eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
Fred Drakecc645b92010-09-04 04:35:34 +0000128 if self.allow_no_value:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000129 eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
Fred Drakecc645b92010-09-04 04:35:34 +0000130 eq(cf.get('NoValue', 'no-such-option-without-value',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000131 fallback=False), False)
Fred Drakecc645b92010-09-04 04:35:34 +0000132
Łukasz Langa26d513c2010-11-10 18:57:39 +0000133 # mapping access
134 eq(cf['Foo Bar']['foo'], 'bar1')
135 eq(cf['Spacey Bar']['foo'], 'bar2')
136 eq(cf['Spacey Bar From The Beginning']['foo'], 'bar3')
137 eq(cf['Spacey Bar From The Beginning']['baz'], 'qwe')
138 eq(cf['Commented Bar']['foo'], 'bar4')
139 eq(cf['Commented Bar']['baz'], 'qwe')
140 eq(cf['Spaces']['key with spaces'], 'value')
141 eq(cf['Spaces']['another with spaces'], 'splat!')
142 eq(cf['Long Line']['foo'],
143 'this line is much, much longer than my editor\nlikes it.')
144 if self.allow_no_value:
145 eq(cf['NoValue']['option-without-value'], None)
146
147 # API access
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000148 self.assertNotIn('__name__', cf.options("Foo Bar"),
149 '__name__ "option" should not be exposed by the API!')
Fred Drakec6f28912002-10-25 19:40:49 +0000150
Łukasz Langa26d513c2010-11-10 18:57:39 +0000151 # mapping access
152 self.assertNotIn('__name__', cf['Foo Bar'],
153 '__name__ "option" should not be exposed by '
154 'mapping protocol access')
155 self.assertFalse('__name__' in cf['Foo Bar'])
156 with self.assertRaises(ValueError):
157 cf['Foo Bar']['__name__']
158 with self.assertRaises(ValueError):
159 del cf['Foo Bar']['__name__']
160 with self.assertRaises(ValueError):
161 cf['Foo Bar']['__name__'] = "can't write to this special name"
162
Fred Drakec6f28912002-10-25 19:40:49 +0000163 # Make sure the right things happen for remove_option();
164 # added to include check for SourceForge bug #123324:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000165
166 # API acceess
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000167 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000168 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000169 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000170 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000171 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000172 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000173 " that was removed")
174
Michael Foordbd6c0792010-07-25 23:09:25 +0000175 with self.assertRaises(configparser.NoSectionError) as cm:
176 cf.remove_option('No Such Section', 'foo')
177 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000178
179 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000180 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000181
Łukasz Langa26d513c2010-11-10 18:57:39 +0000182 # mapping access
183 del cf['Spacey Bar']['foo']
184 self.assertFalse('foo' in cf['Spacey Bar'])
185 with self.assertRaises(KeyError):
186 del cf['Spacey Bar']['foo']
187 with self.assertRaises(KeyError):
188 del cf['No Such Section']['foo']
189
Fred Drakea4923622010-08-09 12:52:45 +0000190 def test_basic(self):
191 config_string = """\
192[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000193foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000194[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000195foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000196[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000197 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000198 baz {0[0]} qwe
199[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000200foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000201baz{0[0]}qwe {1[0]}another one
202[Long Line]
203foo{0[1]} this line is much, much longer than my editor
204 likes it.
205[Section\\with$weird%characters[\t]
206[Internationalized Stuff]
207foo[bg]{0[1]} Bulgarian
208foo{0[0]}Default
209foo[en]{0[0]}English
210foo[de]{0[0]}Deutsch
211[Spaces]
212key with spaces {0[1]} value
213another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000214[Types]
215int {0[1]} 42
216float {0[0]} 0.44
217boolean {0[0]} NO
Fred Drakea4923622010-08-09 12:52:45 +0000218""".format(self.delimiters, self.comment_prefixes)
219 if self.allow_no_value:
220 config_string += (
221 "[NoValue]\n"
222 "option-without-value\n"
223 )
224 cf = self.fromstring(config_string)
225 self.basic_test(cf)
226 if self.strict:
227 with self.assertRaises(configparser.DuplicateOptionError):
228 cf.read_string(textwrap.dedent("""\
229 [Duplicate Options Here]
230 option {0[0]} with a value
231 option {0[1]} with another value
232 """.format(self.delimiters)))
233 with self.assertRaises(configparser.DuplicateSectionError):
234 cf.read_string(textwrap.dedent("""\
235 [And Now For Something]
236 completely different {0[0]} True
237 [And Now For Something]
238 the larch {0[1]} 1
239 """.format(self.delimiters)))
240 else:
241 cf.read_string(textwrap.dedent("""\
242 [Duplicate Options Here]
243 option {0[0]} with a value
244 option {0[1]} with another value
245 """.format(self.delimiters)))
246
247 cf.read_string(textwrap.dedent("""\
248 [And Now For Something]
249 completely different {0[0]} True
250 [And Now For Something]
251 the larch {0[1]} 1
252 """.format(self.delimiters)))
253
254 def test_basic_from_dict(self):
255 config = {
256 "Foo Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000257 "foo": "bar1",
Fred Drakea4923622010-08-09 12:52:45 +0000258 },
259 "Spacey Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000260 "foo": "bar2",
Fred Drakea4923622010-08-09 12:52:45 +0000261 },
262 "Spacey Bar From The Beginning": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000263 "foo": "bar3",
Fred Drakea4923622010-08-09 12:52:45 +0000264 "baz": "qwe",
265 },
266 "Commented Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000267 "foo": "bar4",
Fred Drakea4923622010-08-09 12:52:45 +0000268 "baz": "qwe",
269 },
270 "Long Line": {
271 "foo": "this line is much, much longer than my editor\nlikes "
272 "it.",
273 },
274 "Section\\with$weird%characters[\t": {
275 },
276 "Internationalized Stuff": {
277 "foo[bg]": "Bulgarian",
278 "foo": "Default",
279 "foo[en]": "English",
280 "foo[de]": "Deutsch",
281 },
282 "Spaces": {
283 "key with spaces": "value",
284 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000285 },
286 "Types": {
287 "int": 42,
288 "float": 0.44,
289 "boolean": False,
290 },
Fred Drakea4923622010-08-09 12:52:45 +0000291 }
292 if self.allow_no_value:
293 config.update({
294 "NoValue": {
295 "option-without-value": None,
296 }
297 })
298 cf = self.newconfig()
299 cf.read_dict(config)
300 self.basic_test(cf)
301 if self.strict:
302 with self.assertRaises(configparser.DuplicateOptionError):
303 cf.read_dict({
304 "Duplicate Options Here": {
305 'option': 'with a value',
306 'OPTION': 'with another value',
307 },
308 })
309 else:
310 cf.read_dict({
311 "Duplicate Options Here": {
312 'option': 'with a value',
313 'OPTION': 'with another value',
314 },
315 })
316
317
Fred Drakec6f28912002-10-25 19:40:49 +0000318 def test_case_sensitivity(self):
319 cf = self.newconfig()
320 cf.add_section("A")
321 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000322 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000323 L = cf.sections()
324 L.sort()
325 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000326 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000327 cf.set("a", "B", "value")
328 eq(cf.options("a"), ["b"])
329 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000330 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000331 with self.assertRaises(configparser.NoSectionError):
332 # section names are case-sensitive
333 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000334 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000335 cf.set("A", "A-B", "A-B value")
336 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000337 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000338 cf.has_option("A", opt),
339 "has_option() returned false for option which should exist")
340 eq(cf.options("A"), ["a-b"])
341 eq(cf.options("a"), ["b"])
342 cf.remove_option("a", "B")
343 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000344
Fred Drakec6f28912002-10-25 19:40:49 +0000345 # SF bug #432369:
346 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000347 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000348 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000349 eq(cf.options("MySection"), ["option"])
350 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000351
Fred Drakec6f28912002-10-25 19:40:49 +0000352 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000353 cf = self.fromstring("[section]\n"
354 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000355 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000356 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000357
Fred Drake3c823aa2001-02-26 21:55:34 +0000358
Łukasz Langa26d513c2010-11-10 18:57:39 +0000359 def test_case_sensitivity_mapping_access(self):
360 cf = self.newconfig()
361 cf["A"] = {}
362 cf["a"] = {"B": "value"}
363 cf["B"] = {}
364 L = [section for section in cf]
365 L.sort()
366 eq = self.assertEqual
367 elem_eq = self.assertItemsEqual
368 eq(L, ["A", "B", configparser.DEFAULTSECT, "a"])
369 eq(cf["a"].keys(), {"b"})
370 eq(cf["a"]["b"], "value",
371 "could not locate option, expecting case-insensitive option names")
372 with self.assertRaises(KeyError):
373 # section names are case-sensitive
374 cf["b"]["A"] = "value"
375 self.assertTrue("b" in cf["a"])
376 cf["A"]["A-B"] = "A-B value"
377 for opt in ("a-b", "A-b", "a-B", "A-B"):
378 self.assertTrue(
379 opt in cf["A"],
380 "has_option() returned false for option which should exist")
381 eq(cf["A"].keys(), {"a-b"})
382 eq(cf["a"].keys(), {"b"})
383 del cf["a"]["B"]
384 elem_eq(cf["a"].keys(), {})
385
386 # SF bug #432369:
387 cf = self.fromstring(
388 "[MySection]\nOption{} first line \n\tsecond line \n".format(
389 self.delimiters[0]))
390 eq(cf["MySection"].keys(), {"option"})
391 eq(cf["MySection"]["Option"], "first line\nsecond line")
392
393 # SF bug #561822:
394 cf = self.fromstring("[section]\n"
395 "nekey{}nevalue\n".format(self.delimiters[0]),
396 defaults={"key":"value"})
397 self.assertTrue("Key" in cf["section"])
398
David Goodger68a1abd2004-10-03 15:40:25 +0000399 def test_default_case_sensitivity(self):
400 cf = self.newconfig({"foo": "Bar"})
401 self.assertEqual(
402 cf.get("DEFAULT", "Foo"), "Bar",
403 "could not locate option, expecting case-insensitive option names")
404 cf = self.newconfig({"Foo": "Bar"})
405 self.assertEqual(
406 cf.get("DEFAULT", "Foo"), "Bar",
407 "could not locate option, expecting case-insensitive defaults")
408
Fred Drakec6f28912002-10-25 19:40:49 +0000409 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000410 cf = self.newconfig()
411 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000412 "[Foo]\n"
413 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000414 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000415 "[Foo]\n"
416 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000417 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000418 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000419 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000420 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000421 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000422 "[Foo]\n wrong-indent\n")
423 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000424 # read_file on a real file
425 tricky = support.findfile("cfgparser.3")
426 if self.delimiters[0] == '=':
427 error = configparser.ParsingError
428 expected = (tricky,)
429 else:
430 error = configparser.MissingSectionHeaderError
431 expected = (tricky, 1,
432 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000433 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000434 e = self.parse_error(cf, error, f)
435 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000436
Fred Drakea4923622010-08-09 12:52:45 +0000437 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000438 if hasattr(src, 'readline'):
439 sio = src
440 else:
441 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000442 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000443 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000444 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000445
Fred Drakec6f28912002-10-25 19:40:49 +0000446 def test_query_errors(self):
447 cf = self.newconfig()
448 self.assertEqual(cf.sections(), [],
449 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000450 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000451 "new ConfigParser should have no acknowledged "
452 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000453 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000454 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000455 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000456 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000457 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000458 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000459 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000460 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000461 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000462
Fred Drakea4923622010-08-09 12:52:45 +0000463 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000464 try:
Fred Drakea4923622010-08-09 12:52:45 +0000465 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000466 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000467 return e
468 else:
469 self.fail("expected exception type %s.%s"
470 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000471
Fred Drakec6f28912002-10-25 19:40:49 +0000472 def test_boolean(self):
473 cf = self.fromstring(
474 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000475 "T1{equals}1\n"
476 "T2{equals}TRUE\n"
477 "T3{equals}True\n"
478 "T4{equals}oN\n"
479 "T5{equals}yes\n"
480 "F1{equals}0\n"
481 "F2{equals}FALSE\n"
482 "F3{equals}False\n"
483 "F4{equals}oFF\n"
484 "F5{equals}nO\n"
485 "E1{equals}2\n"
486 "E2{equals}foo\n"
487 "E3{equals}-1\n"
488 "E4{equals}0.1\n"
489 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000490 )
491 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000492 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
493 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000494 self.assertRaises(ValueError,
495 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000496
Fred Drakec6f28912002-10-25 19:40:49 +0000497 def test_weird_errors(self):
498 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000499 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000500 with self.assertRaises(configparser.DuplicateSectionError) as cm:
501 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000502 e = cm.exception
503 self.assertEqual(str(e), "Section 'Foo' already exists")
504 self.assertEqual(e.args, ("Foo", None, None))
505
506 if self.strict:
507 with self.assertRaises(configparser.DuplicateSectionError) as cm:
508 cf.read_string(textwrap.dedent("""\
509 [Foo]
510 will this be added{equals}True
511 [Bar]
512 what about this{equals}True
513 [Foo]
514 oops{equals}this won't
515 """.format(equals=self.delimiters[0])), source='<foo-bar>')
516 e = cm.exception
517 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
518 "section 'Foo' already exists")
519 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
520
521 with self.assertRaises(configparser.DuplicateOptionError) as cm:
522 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
523 e = cm.exception
524 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
525 "in section 'Bar' already exists")
526 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000527
528 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000529 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000530 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000531 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000532 " likes it.\n"
533 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000534 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000535 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000536 "[Long Line - With Comments!]\n"
537 "test {0[1]} we {comment} can\n"
538 " also {comment} place\n"
539 " comments {comment} in\n"
540 " multiline {comment} values"
541 "\n".format(self.delimiters, comment=self.comment_prefixes[0])
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 = (
Fred Drakec6f28912002-10-25 19:40:49 +0000553 "[DEFAULT]\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"
566 "\n".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000567 )
Fred Drake03c44a32010-02-19 06:08:41 +0000568 if self.allow_no_value:
569 expect_string += (
570 "[Valueless]\n"
571 "option-without-value\n"
572 "\n"
573 )
574 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000575
Fred Drakeabc086f2004-05-18 03:29:52 +0000576 def test_set_string_types(self):
577 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000578 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000579 # Check that we don't get an exception when setting values in
580 # an existing section using strings:
581 class mystr(str):
582 pass
583 cf.set("sect", "option1", "splat")
584 cf.set("sect", "option1", mystr("splat"))
585 cf.set("sect", "option2", "splat")
586 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000587 cf.set("sect", "option1", "splat")
588 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000589
Fred Drake82903142004-05-18 04:24:02 +0000590 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000591 if self.delimiters[0] != '=':
592 # skip reading the file if we're using an incompatible format
593 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000594 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000595 # check when we pass a mix of readable and non-readable files:
596 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000597 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000598 self.assertEqual(parsed_files, [file1])
599 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
600 # check when we pass only a filename:
601 cf = self.newconfig()
602 parsed_files = cf.read(file1)
603 self.assertEqual(parsed_files, [file1])
604 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
605 # check when we pass only missing files:
606 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000607 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000608 self.assertEqual(parsed_files, [])
609 # check when we pass no files:
610 cf = self.newconfig()
611 parsed_files = cf.read([])
612 self.assertEqual(parsed_files, [])
613
Fred Drakec6f28912002-10-25 19:40:49 +0000614 # shared by subclasses
615 def get_interpolation_config(self):
616 return self.fromstring(
617 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000618 "bar{equals}something %(with1)s interpolation (1 step)\n"
619 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
620 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
621 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
622 "with11{equals}%(with10)s\n"
623 "with10{equals}%(with9)s\n"
624 "with9{equals}%(with8)s\n"
625 "with8{equals}%(With7)s\n"
626 "with7{equals}%(WITH6)s\n"
627 "with6{equals}%(with5)s\n"
628 "With5{equals}%(with4)s\n"
629 "WITH4{equals}%(with3)s\n"
630 "with3{equals}%(with2)s\n"
631 "with2{equals}%(with1)s\n"
632 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000633 "\n"
634 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000635 "foo{equals}%(bar)s\n"
636 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000637 "\n"
638 "[Interpolation Error]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000639 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]),
Fred Drake54782192002-12-31 06:57:25 +0000640 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000641 defaults={"getname": "%(__name__)s"})
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"
648 "getdefault{0[1]} |%(default)s|\n"
649 "getname{0[1]} |%(__name__)s|".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000650 defaults={"default": "<default>"})
651 L = list(cf.items("section"))
652 L.sort()
653 self.assertEqual(L, expected)
654
Fred Drake8ef67672000-09-27 22:45:25 +0000655
Fred Drakea4923622010-08-09 12:52:45 +0000656class StrictTestCase(BasicTestCase):
657 config_class = configparser.RawConfigParser
658 strict = True
659
660
Georg Brandl96a60ae2010-07-28 13:13:46 +0000661class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000662 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000663
664 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000665 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000666 configparser.ConfigParser: ("something %(with11)s "
667 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000668 configparser.SafeConfigParser: "%(with1)s",
669 }
Fred Drakec6f28912002-10-25 19:40:49 +0000670 cf = self.get_interpolation_config()
671 eq = self.assertEqual
672 eq(cf.get("Foo", "getname"), "Foo")
673 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
674 eq(cf.get("Foo", "bar9"),
675 "something with lots of interpolation (9 steps)")
676 eq(cf.get("Foo", "bar10"),
677 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000678 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000679 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000680
Fred Drake54782192002-12-31 06:57:25 +0000681 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000682 rawval = {
683 configparser.ConfigParser: '%(reference)s',
684 configparser.SafeConfigParser: '',
685 }
Fred Drakea4923622010-08-09 12:52:45 +0000686 cf = self.get_interpolation_config()
687 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000688 "Interpolation Error", "name")
689 self.assertEqual(e.reference, "reference")
690 self.assertEqual(e.section, "Interpolation Error")
691 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000692 self.assertEqual(e.args, ('name', 'Interpolation Error',
693 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000694
Fred Drake98e3b292002-10-25 20:42:44 +0000695 def test_items(self):
696 self.check_items_config([('default', '<default>'),
697 ('getdefault', '|<default>|'),
698 ('getname', '|section|'),
699 ('key', '|value|'),
700 ('name', 'value')])
701
David Goodger1cbf2062004-10-03 15:55:09 +0000702 def test_set_nonstring_types(self):
703 cf = self.newconfig()
704 cf.add_section('non-string')
705 cf.set('non-string', 'int', 1)
706 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
707 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
708 '%(list)': '%(list)'})
709 cf.set('non-string', 'string_with_interpolation', '%(list)s')
710 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
711 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
712 self.assertEqual(cf.get('non-string', 'list', raw=True),
713 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
714 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
715 self.assertEqual(cf.get('non-string', 'dict', raw=True),
716 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
717 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
718 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
719 raw=True), '%(list)s')
720 self.assertRaises(ValueError, cf.get, 'non-string',
721 'string_with_interpolation', raw=False)
722
Georg Brandl96a60ae2010-07-28 13:13:46 +0000723class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
724 delimiters = (':=', '$')
725 comment_prefixes = ('//', '"')
726
727class 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
761 eq(cf.get("Foo", "getname"), "%(__name__)s")
762 eq(cf.get("Foo", "bar"),
763 "something %(with1)s interpolation (1 step)")
764 eq(cf.get("Foo", "bar9"),
765 "something %(with9)s lots of interpolation (9 steps)")
766 eq(cf.get("Foo", "bar10"),
767 "something %(with10)s lots of interpolation (10 steps)")
768 eq(cf.get("Foo", "bar11"),
769 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000770
Fred Drake98e3b292002-10-25 20:42:44 +0000771 def test_items(self):
772 self.check_items_config([('default', '<default>'),
773 ('getdefault', '|%(default)s|'),
774 ('getname', '|%(__name__)s|'),
775 ('key', '|%(name)s|'),
776 ('name', 'value')])
777
David Goodger1cbf2062004-10-03 15:55:09 +0000778 def test_set_nonstring_types(self):
779 cf = self.newconfig()
780 cf.add_section('non-string')
781 cf.set('non-string', 'int', 1)
782 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
783 cf.set('non-string', 'dict', {'pi': 3.14159})
784 self.assertEqual(cf.get('non-string', 'int'), 1)
785 self.assertEqual(cf.get('non-string', 'list'),
786 [0, 1, 1, 2, 3, 5, 8, 13])
787 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000788
Georg Brandl96a60ae2010-07-28 13:13:46 +0000789class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
790 delimiters = (':=', '$')
791 comment_prefixes = ('//', '"')
792
793class RawConfigParserTestSambaConf(BasicTestCase):
794 config_class = configparser.RawConfigParser
795 comment_prefixes = ('#', ';', '//', '----')
796 empty_lines_in_values = False
797
798 def test_reading(self):
799 smbconf = support.findfile("cfgparser.2")
800 # check when we pass a mix of readable and non-readable files:
801 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000802 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000803 self.assertEqual(parsed_files, [smbconf])
804 sections = ['global', 'homes', 'printers',
805 'print$', 'pdf-generator', 'tmp', 'Agustin']
806 self.assertEqual(cf.sections(), sections)
807 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
808 self.assertEqual(cf.getint("global", "max log size"), 50)
809 self.assertEqual(cf.get("global", "hosts allow"), "127.")
810 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000811
Fred Drake0eebd5c2002-10-25 21:52:00 +0000812class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000813 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000814
815 def test_safe_interpolation(self):
816 # See http://www.python.org/sf/511737
817 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000818 "option1{eq}xxx\n"
819 "option2{eq}%(option1)s/xxx\n"
820 "ok{eq}%(option1)s/%%s\n"
821 "not_ok{eq}%(option2)s/%%s".format(
822 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000823 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
824 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
825
Guido van Rossumd8faa362007-04-27 19:54:29 +0000826 def test_set_malformatted_interpolation(self):
827 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000828 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000829
830 self.assertEqual(cf.get('sect', "option1"), "foo")
831
832 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
833 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
834 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
835
836 self.assertEqual(cf.get('sect', "option1"), "foo")
837
Georg Brandl1f9fa312009-04-27 16:42:58 +0000838 # bug #5741: double percents are *not* malformed
839 cf.set("sect", "option2", "foo%%bar")
840 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
841
David Goodger1cbf2062004-10-03 15:55:09 +0000842 def test_set_nonstring_types(self):
843 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000844 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000845 # Check that we get a TypeError when setting non-string values
846 # in an existing section:
847 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
848 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
849 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
850 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
851 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
852 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
853
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000854 def test_add_section_default_1(self):
855 cf = self.newconfig()
856 self.assertRaises(ValueError, cf.add_section, "default")
857
858 def test_add_section_default_2(self):
859 cf = self.newconfig()
860 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
861
Georg Brandl96a60ae2010-07-28 13:13:46 +0000862class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
863 delimiters = (':=', '$')
864 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000865
866class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
867 allow_no_value = True
868
Georg Brandl8dcaa732010-07-29 12:17:40 +0000869class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
870 config_class = configparser.SafeConfigParser
871 delimiters = {'='}
872 comment_prefixes = {'#'}
873 allow_no_value = True
874
875 def test_cfgparser_dot_3(self):
876 tricky = support.findfile("cfgparser.3")
877 cf = self.newconfig()
878 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
879 self.assertEqual(cf.sections(), ['strange',
880 'corruption',
881 'yeah, sections can be '
882 'indented as well',
883 'another one!',
884 'no values here',
885 'tricky interpolation',
886 'more interpolation'])
Fred Drakecc645b92010-09-04 04:35:34 +0000887 self.assertEqual(cf.getint('DEFAULT', 'go',
888 vars={'interpolate': '-1'}), -1)
889 with self.assertRaises(ValueError):
890 # no interpolation will happen
891 cf.getint('DEFAULT', 'go', raw=True, vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000892 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
893 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
894 longname = 'yeah, sections can be indented as well'
895 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
896 self.assertEquals(cf.get(longname, 'lets use some Unicode'),
897 '片仮名')
898 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
899 # `go` from DEFAULT
900 with self.assertRaises(configparser.InterpolationMissingOptionError):
901 cf.items('no values here')
902 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
903 self.assertEqual(cf.get('tricky interpolation', 'lets'),
904 cf.get('tricky interpolation', 'go'))
905 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
906
907 def test_unicode_failure(self):
908 tricky = support.findfile("cfgparser.3")
909 cf = self.newconfig()
910 with self.assertRaises(UnicodeDecodeError):
911 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000912
Fred Drake88444412010-09-03 04:22:36 +0000913
914class Issue7005TestCase(unittest.TestCase):
915 """Test output when None is set() as a value and allow_no_value == False.
916
917 http://bugs.python.org/issue7005
918
919 """
920
921 expected_output = "[section]\noption = None\n\n"
922
923 def prepare(self, config_class):
924 # This is the default, but that's the point.
925 cp = config_class(allow_no_value=False)
926 cp.add_section("section")
927 cp.set("section", "option", None)
928 sio = io.StringIO()
929 cp.write(sio)
930 return sio.getvalue()
931
932 def test_none_as_value_stringified(self):
933 output = self.prepare(configparser.ConfigParser)
934 self.assertEqual(output, self.expected_output)
935
936 def test_none_as_value_stringified_raw(self):
937 output = self.prepare(configparser.RawConfigParser)
938 self.assertEqual(output, self.expected_output)
939
940
Thomas Wouters89f507f2006-12-13 04:49:30 +0000941class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000942 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000943
944 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +0000945 cf = self.fromstring("[b]\n"
946 "o4=1\n"
947 "o3=2\n"
948 "o2=3\n"
949 "o1=4\n"
950 "[a]\n"
951 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000952 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +0000953 cf.write(output)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000954 self.assertEquals(output.getvalue(),
955 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000956 "k = v\n\n"
Thomas Wouters89f507f2006-12-13 04:49:30 +0000957 "[b]\n"
958 "o1 = 4\n"
959 "o2 = 3\n"
960 "o3 = 2\n"
961 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000962
Fred Drake03c44a32010-02-19 06:08:41 +0000963
Georg Brandl96a60ae2010-07-28 13:13:46 +0000964class CompatibleTestCase(CfgParserTestCaseClass):
965 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +0000966 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +0000967
968 def test_comment_handling(self):
969 config_string = textwrap.dedent("""\
970 [Commented Bar]
971 baz=qwe ; a comment
972 foo: bar # not a comment!
973 # but this is a comment
974 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000975 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +0000976 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +0000977 """)
978 cf = self.fromstring(config_string)
979 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
980 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000981 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000982
983
Fred Drakec6f28912002-10-25 19:40:49 +0000984def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000985 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000986 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000987 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000988 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000989 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000990 RawConfigParserTestCaseNonStandardDelimiters,
991 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000992 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000993 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000994 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000995 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000996 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +0000997 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +0000998 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000999 CompatibleTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +00001000 )
1001
Fred Drake3af0eb82002-10-25 18:09:24 +00001002
Fred Drakec6f28912002-10-25 19:40:49 +00001003if __name__ == "__main__":
1004 test_main()