blob: fc8b2ad257fe485ebcd76a7c3075ad6c0b7e1d0d [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
Łukasz Langac264c092010-11-20 16:15:37 +000034 default_section = configparser.DEFAULTSECT
Fred Drake03c44a32010-02-19 06:08:41 +000035
Fred Drakec6f28912002-10-25 19:40:49 +000036 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000037 arguments = dict(
Fred Drakea4923622010-08-09 12:52:45 +000038 defaults=defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000039 allow_no_value=self.allow_no_value,
40 delimiters=self.delimiters,
41 comment_prefixes=self.comment_prefixes,
42 empty_lines_in_values=self.empty_lines_in_values,
43 dict_type=self.dict_type,
Fred Drakea4923622010-08-09 12:52:45 +000044 strict=self.strict,
Łukasz Langac264c092010-11-20 16:15:37 +000045 default_section=self.default_section,
Georg Brandl96a60ae2010-07-28 13:13:46 +000046 )
Fred Drakea4923622010-08-09 12:52:45 +000047 return self.config_class(**arguments)
Fred Drake8ef67672000-09-27 22:45:25 +000048
Fred Drakec6f28912002-10-25 19:40:49 +000049 def fromstring(self, string, defaults=None):
50 cf = self.newconfig(defaults)
Fred Drakea4923622010-08-09 12:52:45 +000051 cf.read_string(string)
Fred Drakec6f28912002-10-25 19:40:49 +000052 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000053
Georg Brandl96a60ae2010-07-28 13:13:46 +000054class BasicTestCase(CfgParserTestCaseClass):
55
Fred Drakea4923622010-08-09 12:52:45 +000056 def basic_test(self, cf):
Georg Brandl96a60ae2010-07-28 13:13:46 +000057 E = ['Commented Bar',
58 'Foo Bar',
59 'Internationalized Stuff',
60 'Long Line',
61 'Section\\with$weird%characters[\t',
62 'Spaces',
63 'Spacey Bar',
64 'Spacey Bar From The Beginning',
Fred Drakecc645b92010-09-04 04:35:34 +000065 'Types',
Fred Drake03c44a32010-02-19 06:08:41 +000066 ]
Łukasz Langa26d513c2010-11-10 18:57:39 +000067
Fred Drake03c44a32010-02-19 06:08:41 +000068 if self.allow_no_value:
Fred Drakecc645b92010-09-04 04:35:34 +000069 E.append('NoValue')
Fred Drake03c44a32010-02-19 06:08:41 +000070 E.sort()
Łukasz Langa26d513c2010-11-10 18:57:39 +000071
72 # API access
73 L = cf.sections()
74 L.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000075 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000076 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000077
Łukasz Langa26d513c2010-11-10 18:57:39 +000078 # mapping access
79 L = [section for section in cf]
80 L.sort()
Łukasz Langac264c092010-11-20 16:15:37 +000081 E.append(self.default_section)
Łukasz Langa26d513c2010-11-10 18:57:39 +000082 E.sort()
83 eq(L, E)
84
Fred Drakec6f28912002-10-25 19:40:49 +000085 # The use of spaces in the section names serves as a
86 # regression test for SourceForge bug #583248:
87 # http://www.python.org/sf/583248
Łukasz Langa26d513c2010-11-10 18:57:39 +000088
89 # API access
90 eq(cf.get('Foo Bar', 'foo'), 'bar1')
91 eq(cf.get('Spacey Bar', 'foo'), 'bar2')
92 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
Georg Brandl96a60ae2010-07-28 13:13:46 +000093 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +000094 eq(cf.get('Commented Bar', 'foo'), 'bar4')
Georg Brandl96a60ae2010-07-28 13:13:46 +000095 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +000096 eq(cf.get('Spaces', 'key with spaces'), 'value')
97 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc645b92010-09-04 04:35:34 +000098 eq(cf.getint('Types', 'int'), 42)
99 eq(cf.get('Types', 'int'), "42")
100 self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
101 eq(cf.get('Types', 'float'), "0.44")
102 eq(cf.getboolean('Types', 'boolean'), False)
Fred Drake03c44a32010-02-19 06:08:41 +0000103 if self.allow_no_value:
104 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000105
Łukasz Langa26d513c2010-11-10 18:57:39 +0000106 # test vars= and fallback=
107 eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
Fred Drakecc645b92010-09-04 04:35:34 +0000108 eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
109 with self.assertRaises(configparser.NoSectionError):
110 cf.get('No Such Foo Bar', 'foo')
111 with self.assertRaises(configparser.NoOptionError):
112 cf.get('Foo Bar', 'no-such-foo')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000113 eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
114 eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
115 eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
116 eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
117 eq(cf.getint('Types', 'int', fallback=18), 42)
118 eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
119 eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
Fred Drakecc645b92010-09-04 04:35:34 +0000120 self.assertAlmostEqual(cf.getfloat('Types', 'float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000121 fallback=0.0), 0.44)
Fred Drakecc645b92010-09-04 04:35:34 +0000122 self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000123 fallback=0.0), 0.0)
124 eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
125 eq(cf.getboolean('Types', 'boolean', fallback=True), False)
126 eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
Fred Drakecc645b92010-09-04 04:35:34 +0000127 "yes") # sic!
Łukasz Langa26d513c2010-11-10 18:57:39 +0000128 eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
129 eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
Fred Drakecc645b92010-09-04 04:35:34 +0000130 if self.allow_no_value:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000131 eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
Fred Drakecc645b92010-09-04 04:35:34 +0000132 eq(cf.get('NoValue', 'no-such-option-without-value',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000133 fallback=False), False)
Fred Drakecc645b92010-09-04 04:35:34 +0000134
Łukasz Langa26d513c2010-11-10 18:57:39 +0000135 # mapping access
136 eq(cf['Foo Bar']['foo'], 'bar1')
137 eq(cf['Spacey Bar']['foo'], 'bar2')
Łukasz Langaa73dc9d2010-11-21 13:56:42 +0000138 section = cf['Spacey Bar From The Beginning']
139 eq(section.name, 'Spacey Bar From The Beginning')
140 self.assertIs(section.parser, cf)
141 with self.assertRaises(AttributeError):
142 section.name = 'Name is read-only'
143 with self.assertRaises(AttributeError):
144 section.parser = 'Parser is read-only'
145 eq(section['foo'], 'bar3')
146 eq(section['baz'], 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000147 eq(cf['Commented Bar']['foo'], 'bar4')
148 eq(cf['Commented Bar']['baz'], 'qwe')
149 eq(cf['Spaces']['key with spaces'], 'value')
150 eq(cf['Spaces']['another with spaces'], 'splat!')
151 eq(cf['Long Line']['foo'],
152 'this line is much, much longer than my editor\nlikes it.')
153 if self.allow_no_value:
154 eq(cf['NoValue']['option-without-value'], None)
155
Fred Drakec6f28912002-10-25 19:40:49 +0000156 # Make sure the right things happen for remove_option();
157 # added to include check for SourceForge bug #123324:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000158
159 # API acceess
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000160 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000161 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000162 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000163 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000164 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000165 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000166 " that was removed")
167
Michael Foordbd6c0792010-07-25 23:09:25 +0000168 with self.assertRaises(configparser.NoSectionError) as cm:
169 cf.remove_option('No Such Section', 'foo')
170 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000171
172 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000173 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000174
Łukasz Langa26d513c2010-11-10 18:57:39 +0000175 # mapping access
176 del cf['Spacey Bar']['foo']
177 self.assertFalse('foo' in cf['Spacey Bar'])
178 with self.assertRaises(KeyError):
179 del cf['Spacey Bar']['foo']
180 with self.assertRaises(KeyError):
181 del cf['No Such Section']['foo']
182
Fred Drakea4923622010-08-09 12:52:45 +0000183 def test_basic(self):
184 config_string = """\
185[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000186foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000187[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000188foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000189[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000190 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000191 baz {0[0]} qwe
192[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000193foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000194baz{0[0]}qwe {1[0]}another one
195[Long Line]
196foo{0[1]} this line is much, much longer than my editor
197 likes it.
198[Section\\with$weird%characters[\t]
199[Internationalized Stuff]
200foo[bg]{0[1]} Bulgarian
201foo{0[0]}Default
202foo[en]{0[0]}English
203foo[de]{0[0]}Deutsch
204[Spaces]
205key with spaces {0[1]} value
206another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000207[Types]
208int {0[1]} 42
209float {0[0]} 0.44
210boolean {0[0]} NO
Fred Drakea4923622010-08-09 12:52:45 +0000211""".format(self.delimiters, self.comment_prefixes)
212 if self.allow_no_value:
213 config_string += (
214 "[NoValue]\n"
215 "option-without-value\n"
216 )
217 cf = self.fromstring(config_string)
218 self.basic_test(cf)
219 if self.strict:
220 with self.assertRaises(configparser.DuplicateOptionError):
221 cf.read_string(textwrap.dedent("""\
222 [Duplicate Options Here]
223 option {0[0]} with a value
224 option {0[1]} with another value
225 """.format(self.delimiters)))
226 with self.assertRaises(configparser.DuplicateSectionError):
227 cf.read_string(textwrap.dedent("""\
228 [And Now For Something]
229 completely different {0[0]} True
230 [And Now For Something]
231 the larch {0[1]} 1
232 """.format(self.delimiters)))
233 else:
234 cf.read_string(textwrap.dedent("""\
235 [Duplicate Options Here]
236 option {0[0]} with a value
237 option {0[1]} with another value
238 """.format(self.delimiters)))
239
240 cf.read_string(textwrap.dedent("""\
241 [And Now For Something]
242 completely different {0[0]} True
243 [And Now For Something]
244 the larch {0[1]} 1
245 """.format(self.delimiters)))
246
247 def test_basic_from_dict(self):
248 config = {
249 "Foo Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000250 "foo": "bar1",
Fred Drakea4923622010-08-09 12:52:45 +0000251 },
252 "Spacey Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000253 "foo": "bar2",
Fred Drakea4923622010-08-09 12:52:45 +0000254 },
255 "Spacey Bar From The Beginning": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000256 "foo": "bar3",
Fred Drakea4923622010-08-09 12:52:45 +0000257 "baz": "qwe",
258 },
259 "Commented Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000260 "foo": "bar4",
Fred Drakea4923622010-08-09 12:52:45 +0000261 "baz": "qwe",
262 },
263 "Long Line": {
264 "foo": "this line is much, much longer than my editor\nlikes "
265 "it.",
266 },
267 "Section\\with$weird%characters[\t": {
268 },
269 "Internationalized Stuff": {
270 "foo[bg]": "Bulgarian",
271 "foo": "Default",
272 "foo[en]": "English",
273 "foo[de]": "Deutsch",
274 },
275 "Spaces": {
276 "key with spaces": "value",
277 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000278 },
279 "Types": {
280 "int": 42,
281 "float": 0.44,
282 "boolean": False,
283 },
Fred Drakea4923622010-08-09 12:52:45 +0000284 }
285 if self.allow_no_value:
286 config.update({
287 "NoValue": {
288 "option-without-value": None,
289 }
290 })
291 cf = self.newconfig()
292 cf.read_dict(config)
293 self.basic_test(cf)
294 if self.strict:
295 with self.assertRaises(configparser.DuplicateOptionError):
296 cf.read_dict({
297 "Duplicate Options Here": {
298 'option': 'with a value',
299 'OPTION': 'with another value',
300 },
301 })
302 else:
303 cf.read_dict({
304 "Duplicate Options Here": {
305 'option': 'with a value',
306 'OPTION': 'with another value',
307 },
308 })
309
310
Fred Drakec6f28912002-10-25 19:40:49 +0000311 def test_case_sensitivity(self):
312 cf = self.newconfig()
313 cf.add_section("A")
314 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000315 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000316 L = cf.sections()
317 L.sort()
318 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000319 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000320 cf.set("a", "B", "value")
321 eq(cf.options("a"), ["b"])
322 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000323 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000324 with self.assertRaises(configparser.NoSectionError):
325 # section names are case-sensitive
326 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000327 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000328 cf.set("A", "A-B", "A-B value")
329 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000330 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000331 cf.has_option("A", opt),
332 "has_option() returned false for option which should exist")
333 eq(cf.options("A"), ["a-b"])
334 eq(cf.options("a"), ["b"])
335 cf.remove_option("a", "B")
336 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000337
Fred Drakec6f28912002-10-25 19:40:49 +0000338 # SF bug #432369:
339 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000340 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000341 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000342 eq(cf.options("MySection"), ["option"])
343 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000344
Fred Drakec6f28912002-10-25 19:40:49 +0000345 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000346 cf = self.fromstring("[section]\n"
347 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000348 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000349 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000350
Fred Drake3c823aa2001-02-26 21:55:34 +0000351
Łukasz Langa26d513c2010-11-10 18:57:39 +0000352 def test_case_sensitivity_mapping_access(self):
353 cf = self.newconfig()
354 cf["A"] = {}
355 cf["a"] = {"B": "value"}
356 cf["B"] = {}
357 L = [section for section in cf]
358 L.sort()
359 eq = self.assertEqual
360 elem_eq = self.assertItemsEqual
Łukasz Langac264c092010-11-20 16:15:37 +0000361 eq(L, sorted(["A", "B", self.default_section, "a"]))
Łukasz Langa26d513c2010-11-10 18:57:39 +0000362 eq(cf["a"].keys(), {"b"})
363 eq(cf["a"]["b"], "value",
364 "could not locate option, expecting case-insensitive option names")
365 with self.assertRaises(KeyError):
366 # section names are case-sensitive
367 cf["b"]["A"] = "value"
368 self.assertTrue("b" in cf["a"])
369 cf["A"]["A-B"] = "A-B value"
370 for opt in ("a-b", "A-b", "a-B", "A-B"):
371 self.assertTrue(
372 opt in cf["A"],
373 "has_option() returned false for option which should exist")
374 eq(cf["A"].keys(), {"a-b"})
375 eq(cf["a"].keys(), {"b"})
376 del cf["a"]["B"]
377 elem_eq(cf["a"].keys(), {})
378
379 # SF bug #432369:
380 cf = self.fromstring(
381 "[MySection]\nOption{} first line \n\tsecond line \n".format(
382 self.delimiters[0]))
383 eq(cf["MySection"].keys(), {"option"})
384 eq(cf["MySection"]["Option"], "first line\nsecond line")
385
386 # SF bug #561822:
387 cf = self.fromstring("[section]\n"
388 "nekey{}nevalue\n".format(self.delimiters[0]),
389 defaults={"key":"value"})
390 self.assertTrue("Key" in cf["section"])
391
David Goodger68a1abd2004-10-03 15:40:25 +0000392 def test_default_case_sensitivity(self):
393 cf = self.newconfig({"foo": "Bar"})
394 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000395 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000396 "could not locate option, expecting case-insensitive option names")
397 cf = self.newconfig({"Foo": "Bar"})
398 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000399 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000400 "could not locate option, expecting case-insensitive defaults")
401
Fred Drakec6f28912002-10-25 19:40:49 +0000402 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000403 cf = self.newconfig()
404 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000405 "[Foo]\n"
406 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000407 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000408 "[Foo]\n"
409 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000410 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000411 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000412 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000413 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000414 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000415 "[Foo]\n wrong-indent\n")
416 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000417 # read_file on a real file
418 tricky = support.findfile("cfgparser.3")
419 if self.delimiters[0] == '=':
420 error = configparser.ParsingError
421 expected = (tricky,)
422 else:
423 error = configparser.MissingSectionHeaderError
424 expected = (tricky, 1,
425 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000426 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000427 e = self.parse_error(cf, error, f)
428 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000429
Fred Drakea4923622010-08-09 12:52:45 +0000430 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000431 if hasattr(src, 'readline'):
432 sio = src
433 else:
434 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000435 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000436 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000437 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000438
Fred Drakec6f28912002-10-25 19:40:49 +0000439 def test_query_errors(self):
440 cf = self.newconfig()
441 self.assertEqual(cf.sections(), [],
442 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000443 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000444 "new ConfigParser should have no acknowledged "
445 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000446 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000447 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000448 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000449 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000450 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000451 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000452 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000453 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000454 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000455
Fred Drakea4923622010-08-09 12:52:45 +0000456 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000457 try:
Fred Drakea4923622010-08-09 12:52:45 +0000458 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000459 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000460 return e
461 else:
462 self.fail("expected exception type %s.%s"
463 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000464
Fred Drakec6f28912002-10-25 19:40:49 +0000465 def test_boolean(self):
466 cf = self.fromstring(
467 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000468 "T1{equals}1\n"
469 "T2{equals}TRUE\n"
470 "T3{equals}True\n"
471 "T4{equals}oN\n"
472 "T5{equals}yes\n"
473 "F1{equals}0\n"
474 "F2{equals}FALSE\n"
475 "F3{equals}False\n"
476 "F4{equals}oFF\n"
477 "F5{equals}nO\n"
478 "E1{equals}2\n"
479 "E2{equals}foo\n"
480 "E3{equals}-1\n"
481 "E4{equals}0.1\n"
482 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000483 )
484 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000485 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
486 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000487 self.assertRaises(ValueError,
488 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000489
Fred Drakec6f28912002-10-25 19:40:49 +0000490 def test_weird_errors(self):
491 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000492 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000493 with self.assertRaises(configparser.DuplicateSectionError) as cm:
494 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000495 e = cm.exception
496 self.assertEqual(str(e), "Section 'Foo' already exists")
497 self.assertEqual(e.args, ("Foo", None, None))
498
499 if self.strict:
500 with self.assertRaises(configparser.DuplicateSectionError) as cm:
501 cf.read_string(textwrap.dedent("""\
502 [Foo]
503 will this be added{equals}True
504 [Bar]
505 what about this{equals}True
506 [Foo]
507 oops{equals}this won't
508 """.format(equals=self.delimiters[0])), source='<foo-bar>')
509 e = cm.exception
510 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
511 "section 'Foo' already exists")
512 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
513
514 with self.assertRaises(configparser.DuplicateOptionError) as cm:
515 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
516 e = cm.exception
517 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
518 "in section 'Bar' already exists")
519 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000520
521 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000522 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000523 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000524 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000525 " likes it.\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000526 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000527 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000528 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000529 "[Long Line - With Comments!]\n"
530 "test {0[1]} we {comment} can\n"
531 " also {comment} place\n"
532 " comments {comment} in\n"
533 " multiline {comment} values"
Łukasz Langac264c092010-11-20 16:15:37 +0000534 "\n".format(self.delimiters, comment=self.comment_prefixes[0],
535 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000536 )
Fred Drake03c44a32010-02-19 06:08:41 +0000537 if self.allow_no_value:
538 config_string += (
539 "[Valueless]\n"
540 "option-without-value\n"
541 )
542
543 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000544 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000545 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000546 expect_string = (
Łukasz Langac264c092010-11-20 16:15:37 +0000547 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000548 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000549 "\tlong line\n"
550 "\n"
551 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000552 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000553 "\tlikes it.\n"
554 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000555 "[Long Line - With Comments!]\n"
556 "test {equals} we\n"
557 "\talso\n"
558 "\tcomments\n"
559 "\tmultiline\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000560 "\n".format(equals=self.delimiters[0],
561 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000562 )
Fred Drake03c44a32010-02-19 06:08:41 +0000563 if self.allow_no_value:
564 expect_string += (
565 "[Valueless]\n"
566 "option-without-value\n"
567 "\n"
568 )
569 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000570
Fred Drakeabc086f2004-05-18 03:29:52 +0000571 def test_set_string_types(self):
572 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000573 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000574 # Check that we don't get an exception when setting values in
575 # an existing section using strings:
576 class mystr(str):
577 pass
578 cf.set("sect", "option1", "splat")
579 cf.set("sect", "option1", mystr("splat"))
580 cf.set("sect", "option2", "splat")
581 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000582 cf.set("sect", "option1", "splat")
583 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000584
Fred Drake82903142004-05-18 04:24:02 +0000585 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000586 if self.delimiters[0] != '=':
587 # skip reading the file if we're using an incompatible format
588 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000589 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000590 # check when we pass a mix of readable and non-readable files:
591 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000592 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000593 self.assertEqual(parsed_files, [file1])
594 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
595 # check when we pass only a filename:
596 cf = self.newconfig()
597 parsed_files = cf.read(file1)
598 self.assertEqual(parsed_files, [file1])
599 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
600 # check when we pass only missing files:
601 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000602 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000603 self.assertEqual(parsed_files, [])
604 # check when we pass no files:
605 cf = self.newconfig()
606 parsed_files = cf.read([])
607 self.assertEqual(parsed_files, [])
608
Fred Drakec6f28912002-10-25 19:40:49 +0000609 # shared by subclasses
610 def get_interpolation_config(self):
611 return self.fromstring(
612 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000613 "bar{equals}something %(with1)s interpolation (1 step)\n"
614 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
615 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
616 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
617 "with11{equals}%(with10)s\n"
618 "with10{equals}%(with9)s\n"
619 "with9{equals}%(with8)s\n"
620 "with8{equals}%(With7)s\n"
621 "with7{equals}%(WITH6)s\n"
622 "with6{equals}%(with5)s\n"
623 "With5{equals}%(with4)s\n"
624 "WITH4{equals}%(with3)s\n"
625 "with3{equals}%(with2)s\n"
626 "with2{equals}%(with1)s\n"
627 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000628 "\n"
629 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000630 "foo{equals}%(bar)s\n"
631 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000632 "\n"
633 "[Interpolation Error]\n"
Fred Drake54782192002-12-31 06:57:25 +0000634 # no definition for 'reference'
Łukasz Langa5c863392010-11-21 13:41:35 +0000635 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
Fred Drake95b96d32001-02-12 17:23:20 +0000636
Fred Drake98e3b292002-10-25 20:42:44 +0000637 def check_items_config(self, expected):
638 cf = self.fromstring(
639 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000640 "name {0[0]} value\n"
641 "key{0[1]} |%(name)s| \n"
Łukasz Langa5c863392010-11-21 13:41:35 +0000642 "getdefault{0[1]} |%(default)s|\n".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000643 defaults={"default": "<default>"})
644 L = list(cf.items("section"))
645 L.sort()
646 self.assertEqual(L, expected)
647
Fred Drake8ef67672000-09-27 22:45:25 +0000648
Fred Drakea4923622010-08-09 12:52:45 +0000649class StrictTestCase(BasicTestCase):
650 config_class = configparser.RawConfigParser
651 strict = True
652
653
Georg Brandl96a60ae2010-07-28 13:13:46 +0000654class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000655 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000656
657 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000658 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000659 configparser.ConfigParser: ("something %(with11)s "
660 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000661 configparser.SafeConfigParser: "%(with1)s",
662 }
Fred Drakec6f28912002-10-25 19:40:49 +0000663 cf = self.get_interpolation_config()
664 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000665 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
666 eq(cf.get("Foo", "bar9"),
667 "something with lots of interpolation (9 steps)")
668 eq(cf.get("Foo", "bar10"),
669 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000670 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000671 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000672
Fred Drake54782192002-12-31 06:57:25 +0000673 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000674 rawval = {
675 configparser.ConfigParser: '%(reference)s',
676 configparser.SafeConfigParser: '',
677 }
Fred Drakea4923622010-08-09 12:52:45 +0000678 cf = self.get_interpolation_config()
679 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000680 "Interpolation Error", "name")
681 self.assertEqual(e.reference, "reference")
682 self.assertEqual(e.section, "Interpolation Error")
683 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000684 self.assertEqual(e.args, ('name', 'Interpolation Error',
685 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000686
Fred Drake98e3b292002-10-25 20:42:44 +0000687 def test_items(self):
688 self.check_items_config([('default', '<default>'),
689 ('getdefault', '|<default>|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000690 ('key', '|value|'),
691 ('name', 'value')])
692
David Goodger1cbf2062004-10-03 15:55:09 +0000693 def test_set_nonstring_types(self):
694 cf = self.newconfig()
695 cf.add_section('non-string')
696 cf.set('non-string', 'int', 1)
697 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
698 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
699 '%(list)': '%(list)'})
700 cf.set('non-string', 'string_with_interpolation', '%(list)s')
701 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
702 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
703 self.assertEqual(cf.get('non-string', 'list', raw=True),
704 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
705 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
706 self.assertEqual(cf.get('non-string', 'dict', raw=True),
707 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
708 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
709 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
710 raw=True), '%(list)s')
711 self.assertRaises(ValueError, cf.get, 'non-string',
712 'string_with_interpolation', raw=False)
713
Georg Brandl96a60ae2010-07-28 13:13:46 +0000714class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
715 delimiters = (':=', '$')
716 comment_prefixes = ('//', '"')
717
Łukasz Langac264c092010-11-20 16:15:37 +0000718class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
719 default_section = 'general'
720
Georg Brandl96a60ae2010-07-28 13:13:46 +0000721class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000722 config_class = configparser.ConfigParser
723 wonderful_spam = ("I'm having spam spam spam spam "
724 "spam spam spam beaked beans spam "
725 "spam spam and spam!").replace(' ', '\t\n')
726
727 def setUp(self):
728 cf = self.newconfig()
729 for i in range(100):
730 s = 'section{}'.format(i)
731 cf.add_section(s)
732 for j in range(10):
733 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
734 with open(support.TESTFN, 'w') as f:
735 cf.write(f)
736
737 def tearDown(self):
738 os.unlink(support.TESTFN)
739
740 def test_dominating_multiline_values(self):
741 # We're reading from file because this is where the code changed
742 # during performance updates in Python 3.2
743 cf_from_file = self.newconfig()
744 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000745 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000746 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
747 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000748
Georg Brandl96a60ae2010-07-28 13:13:46 +0000749class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000750 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000751
752 def test_interpolation(self):
753 cf = self.get_interpolation_config()
754 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000755 eq(cf.get("Foo", "bar"),
756 "something %(with1)s interpolation (1 step)")
757 eq(cf.get("Foo", "bar9"),
758 "something %(with9)s lots of interpolation (9 steps)")
759 eq(cf.get("Foo", "bar10"),
760 "something %(with10)s lots of interpolation (10 steps)")
761 eq(cf.get("Foo", "bar11"),
762 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000763
Fred Drake98e3b292002-10-25 20:42:44 +0000764 def test_items(self):
765 self.check_items_config([('default', '<default>'),
766 ('getdefault', '|%(default)s|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000767 ('key', '|%(name)s|'),
768 ('name', 'value')])
769
David Goodger1cbf2062004-10-03 15:55:09 +0000770 def test_set_nonstring_types(self):
771 cf = self.newconfig()
772 cf.add_section('non-string')
773 cf.set('non-string', 'int', 1)
774 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
775 cf.set('non-string', 'dict', {'pi': 3.14159})
776 self.assertEqual(cf.get('non-string', 'int'), 1)
777 self.assertEqual(cf.get('non-string', 'list'),
778 [0, 1, 1, 2, 3, 5, 8, 13])
779 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000780
Georg Brandl96a60ae2010-07-28 13:13:46 +0000781class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
782 delimiters = (':=', '$')
783 comment_prefixes = ('//', '"')
784
785class RawConfigParserTestSambaConf(BasicTestCase):
786 config_class = configparser.RawConfigParser
787 comment_prefixes = ('#', ';', '//', '----')
788 empty_lines_in_values = False
789
790 def test_reading(self):
791 smbconf = support.findfile("cfgparser.2")
792 # check when we pass a mix of readable and non-readable files:
793 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000794 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000795 self.assertEqual(parsed_files, [smbconf])
796 sections = ['global', 'homes', 'printers',
797 'print$', 'pdf-generator', 'tmp', 'Agustin']
798 self.assertEqual(cf.sections(), sections)
799 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
800 self.assertEqual(cf.getint("global", "max log size"), 50)
801 self.assertEqual(cf.get("global", "hosts allow"), "127.")
802 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000803
Fred Drake0eebd5c2002-10-25 21:52:00 +0000804class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000805 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000806
807 def test_safe_interpolation(self):
808 # See http://www.python.org/sf/511737
809 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000810 "option1{eq}xxx\n"
811 "option2{eq}%(option1)s/xxx\n"
812 "ok{eq}%(option1)s/%%s\n"
813 "not_ok{eq}%(option2)s/%%s".format(
814 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000815 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
816 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
817
Guido van Rossumd8faa362007-04-27 19:54:29 +0000818 def test_set_malformatted_interpolation(self):
819 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000820 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000821
822 self.assertEqual(cf.get('sect', "option1"), "foo")
823
824 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
825 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
826 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
827
828 self.assertEqual(cf.get('sect', "option1"), "foo")
829
Georg Brandl1f9fa312009-04-27 16:42:58 +0000830 # bug #5741: double percents are *not* malformed
831 cf.set("sect", "option2", "foo%%bar")
832 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
833
David Goodger1cbf2062004-10-03 15:55:09 +0000834 def test_set_nonstring_types(self):
835 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000836 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000837 # Check that we get a TypeError when setting non-string values
838 # in an existing section:
839 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
840 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
841 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
842 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
843 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
844 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
845
Łukasz Langac264c092010-11-20 16:15:37 +0000846 def test_add_section_default(self):
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000847 cf = self.newconfig()
Łukasz Langac264c092010-11-20 16:15:37 +0000848 self.assertRaises(ValueError, cf.add_section, self.default_section)
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000849
Georg Brandl96a60ae2010-07-28 13:13:46 +0000850class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
851 delimiters = (':=', '$')
852 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000853
854class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
855 allow_no_value = True
856
Georg Brandl8dcaa732010-07-29 12:17:40 +0000857class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
858 config_class = configparser.SafeConfigParser
859 delimiters = {'='}
860 comment_prefixes = {'#'}
861 allow_no_value = True
862
863 def test_cfgparser_dot_3(self):
864 tricky = support.findfile("cfgparser.3")
865 cf = self.newconfig()
866 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
867 self.assertEqual(cf.sections(), ['strange',
868 'corruption',
869 'yeah, sections can be '
870 'indented as well',
871 'another one!',
872 'no values here',
873 'tricky interpolation',
874 'more interpolation'])
Łukasz Langac264c092010-11-20 16:15:37 +0000875 self.assertEqual(cf.getint(self.default_section, 'go',
Fred Drakecc645b92010-09-04 04:35:34 +0000876 vars={'interpolate': '-1'}), -1)
877 with self.assertRaises(ValueError):
878 # no interpolation will happen
Łukasz Langac264c092010-11-20 16:15:37 +0000879 cf.getint(self.default_section, 'go', raw=True,
880 vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000881 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
882 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
883 longname = 'yeah, sections can be indented as well'
884 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000885 self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000886 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
887 # `go` from DEFAULT
888 with self.assertRaises(configparser.InterpolationMissingOptionError):
889 cf.items('no values here')
890 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
891 self.assertEqual(cf.get('tricky interpolation', 'lets'),
892 cf.get('tricky interpolation', 'go'))
893 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
894
895 def test_unicode_failure(self):
896 tricky = support.findfile("cfgparser.3")
897 cf = self.newconfig()
898 with self.assertRaises(UnicodeDecodeError):
899 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000900
Fred Drake88444412010-09-03 04:22:36 +0000901
902class Issue7005TestCase(unittest.TestCase):
903 """Test output when None is set() as a value and allow_no_value == False.
904
905 http://bugs.python.org/issue7005
906
907 """
908
909 expected_output = "[section]\noption = None\n\n"
910
911 def prepare(self, config_class):
912 # This is the default, but that's the point.
913 cp = config_class(allow_no_value=False)
914 cp.add_section("section")
915 cp.set("section", "option", None)
916 sio = io.StringIO()
917 cp.write(sio)
918 return sio.getvalue()
919
920 def test_none_as_value_stringified(self):
921 output = self.prepare(configparser.ConfigParser)
922 self.assertEqual(output, self.expected_output)
923
924 def test_none_as_value_stringified_raw(self):
925 output = self.prepare(configparser.RawConfigParser)
926 self.assertEqual(output, self.expected_output)
927
928
Thomas Wouters89f507f2006-12-13 04:49:30 +0000929class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000930 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000931
932 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +0000933 cf = self.fromstring("[b]\n"
934 "o4=1\n"
935 "o3=2\n"
936 "o2=3\n"
937 "o1=4\n"
938 "[a]\n"
939 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000940 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +0000941 cf.write(output)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000942 self.assertEqual(output.getvalue(),
943 "[a]\n"
944 "k = v\n\n"
945 "[b]\n"
946 "o1 = 4\n"
947 "o2 = 3\n"
948 "o3 = 2\n"
949 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000950
Fred Drake03c44a32010-02-19 06:08:41 +0000951
Georg Brandl96a60ae2010-07-28 13:13:46 +0000952class CompatibleTestCase(CfgParserTestCaseClass):
953 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +0000954 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +0000955
956 def test_comment_handling(self):
957 config_string = textwrap.dedent("""\
958 [Commented Bar]
959 baz=qwe ; a comment
960 foo: bar # not a comment!
961 # but this is a comment
962 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000963 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +0000964 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +0000965 """)
966 cf = self.fromstring(config_string)
967 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
968 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000969 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000970
971
Fred Drakec6f28912002-10-25 19:40:49 +0000972def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000973 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000974 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000975 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000976 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000977 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000978 RawConfigParserTestCaseNonStandardDelimiters,
979 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000980 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000981 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000982 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000983 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000984 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +0000985 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +0000986 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000987 CompatibleTestCase,
Łukasz Langac264c092010-11-20 16:15:37 +0000988 ConfigParserTestCaseNonStandardDefaultSection,
Fred Drake03c44a32010-02-19 06:08:41 +0000989 )
990
Fred Drake3af0eb82002-10-25 18:09:24 +0000991
Fred Drakec6f28912002-10-25 19:40:49 +0000992if __name__ == "__main__":
993 test_main()