blob: 4faf90cf1f1684bab16d2a876a5f95564fca20e1 [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')
138 eq(cf['Spacey Bar From The Beginning']['foo'], 'bar3')
139 eq(cf['Spacey Bar From The Beginning']['baz'], 'qwe')
140 eq(cf['Commented Bar']['foo'], 'bar4')
141 eq(cf['Commented Bar']['baz'], 'qwe')
142 eq(cf['Spaces']['key with spaces'], 'value')
143 eq(cf['Spaces']['another with spaces'], 'splat!')
144 eq(cf['Long Line']['foo'],
145 'this line is much, much longer than my editor\nlikes it.')
146 if self.allow_no_value:
147 eq(cf['NoValue']['option-without-value'], None)
148
Fred Drakec6f28912002-10-25 19:40:49 +0000149 # Make sure the right things happen for remove_option();
150 # added to include check for SourceForge bug #123324:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000151
152 # API acceess
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000153 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000154 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000155 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000156 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000157 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000158 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000159 " that was removed")
160
Michael Foordbd6c0792010-07-25 23:09:25 +0000161 with self.assertRaises(configparser.NoSectionError) as cm:
162 cf.remove_option('No Such Section', 'foo')
163 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000164
165 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000166 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000167
Łukasz Langa26d513c2010-11-10 18:57:39 +0000168 # mapping access
169 del cf['Spacey Bar']['foo']
170 self.assertFalse('foo' in cf['Spacey Bar'])
171 with self.assertRaises(KeyError):
172 del cf['Spacey Bar']['foo']
173 with self.assertRaises(KeyError):
174 del cf['No Such Section']['foo']
175
Fred Drakea4923622010-08-09 12:52:45 +0000176 def test_basic(self):
177 config_string = """\
178[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000179foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000180[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000181foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000182[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000183 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000184 baz {0[0]} qwe
185[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000186foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000187baz{0[0]}qwe {1[0]}another one
188[Long Line]
189foo{0[1]} this line is much, much longer than my editor
190 likes it.
191[Section\\with$weird%characters[\t]
192[Internationalized Stuff]
193foo[bg]{0[1]} Bulgarian
194foo{0[0]}Default
195foo[en]{0[0]}English
196foo[de]{0[0]}Deutsch
197[Spaces]
198key with spaces {0[1]} value
199another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000200[Types]
201int {0[1]} 42
202float {0[0]} 0.44
203boolean {0[0]} NO
Fred Drakea4923622010-08-09 12:52:45 +0000204""".format(self.delimiters, self.comment_prefixes)
205 if self.allow_no_value:
206 config_string += (
207 "[NoValue]\n"
208 "option-without-value\n"
209 )
210 cf = self.fromstring(config_string)
211 self.basic_test(cf)
212 if self.strict:
213 with self.assertRaises(configparser.DuplicateOptionError):
214 cf.read_string(textwrap.dedent("""\
215 [Duplicate Options Here]
216 option {0[0]} with a value
217 option {0[1]} with another value
218 """.format(self.delimiters)))
219 with self.assertRaises(configparser.DuplicateSectionError):
220 cf.read_string(textwrap.dedent("""\
221 [And Now For Something]
222 completely different {0[0]} True
223 [And Now For Something]
224 the larch {0[1]} 1
225 """.format(self.delimiters)))
226 else:
227 cf.read_string(textwrap.dedent("""\
228 [Duplicate Options Here]
229 option {0[0]} with a value
230 option {0[1]} with another value
231 """.format(self.delimiters)))
232
233 cf.read_string(textwrap.dedent("""\
234 [And Now For Something]
235 completely different {0[0]} True
236 [And Now For Something]
237 the larch {0[1]} 1
238 """.format(self.delimiters)))
239
240 def test_basic_from_dict(self):
241 config = {
242 "Foo Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000243 "foo": "bar1",
Fred Drakea4923622010-08-09 12:52:45 +0000244 },
245 "Spacey Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000246 "foo": "bar2",
Fred Drakea4923622010-08-09 12:52:45 +0000247 },
248 "Spacey Bar From The Beginning": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000249 "foo": "bar3",
Fred Drakea4923622010-08-09 12:52:45 +0000250 "baz": "qwe",
251 },
252 "Commented Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000253 "foo": "bar4",
Fred Drakea4923622010-08-09 12:52:45 +0000254 "baz": "qwe",
255 },
256 "Long Line": {
257 "foo": "this line is much, much longer than my editor\nlikes "
258 "it.",
259 },
260 "Section\\with$weird%characters[\t": {
261 },
262 "Internationalized Stuff": {
263 "foo[bg]": "Bulgarian",
264 "foo": "Default",
265 "foo[en]": "English",
266 "foo[de]": "Deutsch",
267 },
268 "Spaces": {
269 "key with spaces": "value",
270 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000271 },
272 "Types": {
273 "int": 42,
274 "float": 0.44,
275 "boolean": False,
276 },
Fred Drakea4923622010-08-09 12:52:45 +0000277 }
278 if self.allow_no_value:
279 config.update({
280 "NoValue": {
281 "option-without-value": None,
282 }
283 })
284 cf = self.newconfig()
285 cf.read_dict(config)
286 self.basic_test(cf)
287 if self.strict:
288 with self.assertRaises(configparser.DuplicateOptionError):
289 cf.read_dict({
290 "Duplicate Options Here": {
291 'option': 'with a value',
292 'OPTION': 'with another value',
293 },
294 })
295 else:
296 cf.read_dict({
297 "Duplicate Options Here": {
298 'option': 'with a value',
299 'OPTION': 'with another value',
300 },
301 })
302
303
Fred Drakec6f28912002-10-25 19:40:49 +0000304 def test_case_sensitivity(self):
305 cf = self.newconfig()
306 cf.add_section("A")
307 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000308 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000309 L = cf.sections()
310 L.sort()
311 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000312 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000313 cf.set("a", "B", "value")
314 eq(cf.options("a"), ["b"])
315 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000316 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000317 with self.assertRaises(configparser.NoSectionError):
318 # section names are case-sensitive
319 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000320 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000321 cf.set("A", "A-B", "A-B value")
322 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000323 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000324 cf.has_option("A", opt),
325 "has_option() returned false for option which should exist")
326 eq(cf.options("A"), ["a-b"])
327 eq(cf.options("a"), ["b"])
328 cf.remove_option("a", "B")
329 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000330
Fred Drakec6f28912002-10-25 19:40:49 +0000331 # SF bug #432369:
332 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000333 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000334 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000335 eq(cf.options("MySection"), ["option"])
336 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000337
Fred Drakec6f28912002-10-25 19:40:49 +0000338 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000339 cf = self.fromstring("[section]\n"
340 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000341 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000342 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000343
Fred Drake3c823aa2001-02-26 21:55:34 +0000344
Łukasz Langa26d513c2010-11-10 18:57:39 +0000345 def test_case_sensitivity_mapping_access(self):
346 cf = self.newconfig()
347 cf["A"] = {}
348 cf["a"] = {"B": "value"}
349 cf["B"] = {}
350 L = [section for section in cf]
351 L.sort()
352 eq = self.assertEqual
353 elem_eq = self.assertItemsEqual
Łukasz Langac264c092010-11-20 16:15:37 +0000354 eq(L, sorted(["A", "B", self.default_section, "a"]))
Łukasz Langa26d513c2010-11-10 18:57:39 +0000355 eq(cf["a"].keys(), {"b"})
356 eq(cf["a"]["b"], "value",
357 "could not locate option, expecting case-insensitive option names")
358 with self.assertRaises(KeyError):
359 # section names are case-sensitive
360 cf["b"]["A"] = "value"
361 self.assertTrue("b" in cf["a"])
362 cf["A"]["A-B"] = "A-B value"
363 for opt in ("a-b", "A-b", "a-B", "A-B"):
364 self.assertTrue(
365 opt in cf["A"],
366 "has_option() returned false for option which should exist")
367 eq(cf["A"].keys(), {"a-b"})
368 eq(cf["a"].keys(), {"b"})
369 del cf["a"]["B"]
370 elem_eq(cf["a"].keys(), {})
371
372 # SF bug #432369:
373 cf = self.fromstring(
374 "[MySection]\nOption{} first line \n\tsecond line \n".format(
375 self.delimiters[0]))
376 eq(cf["MySection"].keys(), {"option"})
377 eq(cf["MySection"]["Option"], "first line\nsecond line")
378
379 # SF bug #561822:
380 cf = self.fromstring("[section]\n"
381 "nekey{}nevalue\n".format(self.delimiters[0]),
382 defaults={"key":"value"})
383 self.assertTrue("Key" in cf["section"])
384
David Goodger68a1abd2004-10-03 15:40:25 +0000385 def test_default_case_sensitivity(self):
386 cf = self.newconfig({"foo": "Bar"})
387 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000388 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000389 "could not locate option, expecting case-insensitive option names")
390 cf = self.newconfig({"Foo": "Bar"})
391 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000392 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000393 "could not locate option, expecting case-insensitive defaults")
394
Fred Drakec6f28912002-10-25 19:40:49 +0000395 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000396 cf = self.newconfig()
397 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000398 "[Foo]\n"
399 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000400 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000401 "[Foo]\n"
402 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000403 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000404 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000405 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000406 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000407 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000408 "[Foo]\n wrong-indent\n")
409 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000410 # read_file on a real file
411 tricky = support.findfile("cfgparser.3")
412 if self.delimiters[0] == '=':
413 error = configparser.ParsingError
414 expected = (tricky,)
415 else:
416 error = configparser.MissingSectionHeaderError
417 expected = (tricky, 1,
418 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000419 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000420 e = self.parse_error(cf, error, f)
421 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000422
Fred Drakea4923622010-08-09 12:52:45 +0000423 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000424 if hasattr(src, 'readline'):
425 sio = src
426 else:
427 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000428 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000429 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000430 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000431
Fred Drakec6f28912002-10-25 19:40:49 +0000432 def test_query_errors(self):
433 cf = self.newconfig()
434 self.assertEqual(cf.sections(), [],
435 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000436 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000437 "new ConfigParser should have no acknowledged "
438 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000439 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000440 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000441 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000442 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000443 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000444 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000445 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000446 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000447 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000448
Fred Drakea4923622010-08-09 12:52:45 +0000449 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000450 try:
Fred Drakea4923622010-08-09 12:52:45 +0000451 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000452 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000453 return e
454 else:
455 self.fail("expected exception type %s.%s"
456 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000457
Fred Drakec6f28912002-10-25 19:40:49 +0000458 def test_boolean(self):
459 cf = self.fromstring(
460 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000461 "T1{equals}1\n"
462 "T2{equals}TRUE\n"
463 "T3{equals}True\n"
464 "T4{equals}oN\n"
465 "T5{equals}yes\n"
466 "F1{equals}0\n"
467 "F2{equals}FALSE\n"
468 "F3{equals}False\n"
469 "F4{equals}oFF\n"
470 "F5{equals}nO\n"
471 "E1{equals}2\n"
472 "E2{equals}foo\n"
473 "E3{equals}-1\n"
474 "E4{equals}0.1\n"
475 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000476 )
477 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000478 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
479 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000480 self.assertRaises(ValueError,
481 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000482
Fred Drakec6f28912002-10-25 19:40:49 +0000483 def test_weird_errors(self):
484 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000485 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000486 with self.assertRaises(configparser.DuplicateSectionError) as cm:
487 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000488 e = cm.exception
489 self.assertEqual(str(e), "Section 'Foo' already exists")
490 self.assertEqual(e.args, ("Foo", None, None))
491
492 if self.strict:
493 with self.assertRaises(configparser.DuplicateSectionError) as cm:
494 cf.read_string(textwrap.dedent("""\
495 [Foo]
496 will this be added{equals}True
497 [Bar]
498 what about this{equals}True
499 [Foo]
500 oops{equals}this won't
501 """.format(equals=self.delimiters[0])), source='<foo-bar>')
502 e = cm.exception
503 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
504 "section 'Foo' already exists")
505 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
506
507 with self.assertRaises(configparser.DuplicateOptionError) as cm:
508 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
509 e = cm.exception
510 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
511 "in section 'Bar' already exists")
512 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000513
514 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000515 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000516 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000517 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000518 " likes it.\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000519 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000520 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000521 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000522 "[Long Line - With Comments!]\n"
523 "test {0[1]} we {comment} can\n"
524 " also {comment} place\n"
525 " comments {comment} in\n"
526 " multiline {comment} values"
Łukasz Langac264c092010-11-20 16:15:37 +0000527 "\n".format(self.delimiters, comment=self.comment_prefixes[0],
528 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000529 )
Fred Drake03c44a32010-02-19 06:08:41 +0000530 if self.allow_no_value:
531 config_string += (
532 "[Valueless]\n"
533 "option-without-value\n"
534 )
535
536 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000537 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000538 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000539 expect_string = (
Łukasz Langac264c092010-11-20 16:15:37 +0000540 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000541 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000542 "\tlong line\n"
543 "\n"
544 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000545 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000546 "\tlikes it.\n"
547 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000548 "[Long Line - With Comments!]\n"
549 "test {equals} we\n"
550 "\talso\n"
551 "\tcomments\n"
552 "\tmultiline\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000553 "\n".format(equals=self.delimiters[0],
554 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000555 )
Fred Drake03c44a32010-02-19 06:08:41 +0000556 if self.allow_no_value:
557 expect_string += (
558 "[Valueless]\n"
559 "option-without-value\n"
560 "\n"
561 )
562 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000563
Fred Drakeabc086f2004-05-18 03:29:52 +0000564 def test_set_string_types(self):
565 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000566 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000567 # Check that we don't get an exception when setting values in
568 # an existing section using strings:
569 class mystr(str):
570 pass
571 cf.set("sect", "option1", "splat")
572 cf.set("sect", "option1", mystr("splat"))
573 cf.set("sect", "option2", "splat")
574 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000575 cf.set("sect", "option1", "splat")
576 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000577
Fred Drake82903142004-05-18 04:24:02 +0000578 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000579 if self.delimiters[0] != '=':
580 # skip reading the file if we're using an incompatible format
581 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000582 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000583 # check when we pass a mix of readable and non-readable files:
584 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000585 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000586 self.assertEqual(parsed_files, [file1])
587 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
588 # check when we pass only a filename:
589 cf = self.newconfig()
590 parsed_files = cf.read(file1)
591 self.assertEqual(parsed_files, [file1])
592 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
593 # check when we pass only missing files:
594 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000595 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000596 self.assertEqual(parsed_files, [])
597 # check when we pass no files:
598 cf = self.newconfig()
599 parsed_files = cf.read([])
600 self.assertEqual(parsed_files, [])
601
Fred Drakec6f28912002-10-25 19:40:49 +0000602 # shared by subclasses
603 def get_interpolation_config(self):
604 return self.fromstring(
605 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000606 "bar{equals}something %(with1)s interpolation (1 step)\n"
607 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
608 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
609 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
610 "with11{equals}%(with10)s\n"
611 "with10{equals}%(with9)s\n"
612 "with9{equals}%(with8)s\n"
613 "with8{equals}%(With7)s\n"
614 "with7{equals}%(WITH6)s\n"
615 "with6{equals}%(with5)s\n"
616 "With5{equals}%(with4)s\n"
617 "WITH4{equals}%(with3)s\n"
618 "with3{equals}%(with2)s\n"
619 "with2{equals}%(with1)s\n"
620 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000621 "\n"
622 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000623 "foo{equals}%(bar)s\n"
624 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000625 "\n"
626 "[Interpolation Error]\n"
Fred Drake54782192002-12-31 06:57:25 +0000627 # no definition for 'reference'
Łukasz Langa5c863392010-11-21 13:41:35 +0000628 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
Fred Drake95b96d32001-02-12 17:23:20 +0000629
Fred Drake98e3b292002-10-25 20:42:44 +0000630 def check_items_config(self, expected):
631 cf = self.fromstring(
632 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000633 "name {0[0]} value\n"
634 "key{0[1]} |%(name)s| \n"
Łukasz Langa5c863392010-11-21 13:41:35 +0000635 "getdefault{0[1]} |%(default)s|\n".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000636 defaults={"default": "<default>"})
637 L = list(cf.items("section"))
638 L.sort()
639 self.assertEqual(L, expected)
640
Fred Drake8ef67672000-09-27 22:45:25 +0000641
Fred Drakea4923622010-08-09 12:52:45 +0000642class StrictTestCase(BasicTestCase):
643 config_class = configparser.RawConfigParser
644 strict = True
645
646
Georg Brandl96a60ae2010-07-28 13:13:46 +0000647class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000648 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000649
650 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000651 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000652 configparser.ConfigParser: ("something %(with11)s "
653 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000654 configparser.SafeConfigParser: "%(with1)s",
655 }
Fred Drakec6f28912002-10-25 19:40:49 +0000656 cf = self.get_interpolation_config()
657 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000658 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
659 eq(cf.get("Foo", "bar9"),
660 "something with lots of interpolation (9 steps)")
661 eq(cf.get("Foo", "bar10"),
662 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000663 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000664 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000665
Fred Drake54782192002-12-31 06:57:25 +0000666 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000667 rawval = {
668 configparser.ConfigParser: '%(reference)s',
669 configparser.SafeConfigParser: '',
670 }
Fred Drakea4923622010-08-09 12:52:45 +0000671 cf = self.get_interpolation_config()
672 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000673 "Interpolation Error", "name")
674 self.assertEqual(e.reference, "reference")
675 self.assertEqual(e.section, "Interpolation Error")
676 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000677 self.assertEqual(e.args, ('name', 'Interpolation Error',
678 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000679
Fred Drake98e3b292002-10-25 20:42:44 +0000680 def test_items(self):
681 self.check_items_config([('default', '<default>'),
682 ('getdefault', '|<default>|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000683 ('key', '|value|'),
684 ('name', 'value')])
685
David Goodger1cbf2062004-10-03 15:55:09 +0000686 def test_set_nonstring_types(self):
687 cf = self.newconfig()
688 cf.add_section('non-string')
689 cf.set('non-string', 'int', 1)
690 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
691 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
692 '%(list)': '%(list)'})
693 cf.set('non-string', 'string_with_interpolation', '%(list)s')
694 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
695 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
696 self.assertEqual(cf.get('non-string', 'list', raw=True),
697 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
698 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
699 self.assertEqual(cf.get('non-string', 'dict', raw=True),
700 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
701 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
702 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
703 raw=True), '%(list)s')
704 self.assertRaises(ValueError, cf.get, 'non-string',
705 'string_with_interpolation', raw=False)
706
Georg Brandl96a60ae2010-07-28 13:13:46 +0000707class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
708 delimiters = (':=', '$')
709 comment_prefixes = ('//', '"')
710
Łukasz Langac264c092010-11-20 16:15:37 +0000711class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
712 default_section = 'general'
713
Georg Brandl96a60ae2010-07-28 13:13:46 +0000714class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000715 config_class = configparser.ConfigParser
716 wonderful_spam = ("I'm having spam spam spam spam "
717 "spam spam spam beaked beans spam "
718 "spam spam and spam!").replace(' ', '\t\n')
719
720 def setUp(self):
721 cf = self.newconfig()
722 for i in range(100):
723 s = 'section{}'.format(i)
724 cf.add_section(s)
725 for j in range(10):
726 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
727 with open(support.TESTFN, 'w') as f:
728 cf.write(f)
729
730 def tearDown(self):
731 os.unlink(support.TESTFN)
732
733 def test_dominating_multiline_values(self):
734 # We're reading from file because this is where the code changed
735 # during performance updates in Python 3.2
736 cf_from_file = self.newconfig()
737 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000738 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000739 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
740 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000741
Georg Brandl96a60ae2010-07-28 13:13:46 +0000742class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000743 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000744
745 def test_interpolation(self):
746 cf = self.get_interpolation_config()
747 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000748 eq(cf.get("Foo", "bar"),
749 "something %(with1)s interpolation (1 step)")
750 eq(cf.get("Foo", "bar9"),
751 "something %(with9)s lots of interpolation (9 steps)")
752 eq(cf.get("Foo", "bar10"),
753 "something %(with10)s lots of interpolation (10 steps)")
754 eq(cf.get("Foo", "bar11"),
755 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000756
Fred Drake98e3b292002-10-25 20:42:44 +0000757 def test_items(self):
758 self.check_items_config([('default', '<default>'),
759 ('getdefault', '|%(default)s|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000760 ('key', '|%(name)s|'),
761 ('name', 'value')])
762
David Goodger1cbf2062004-10-03 15:55:09 +0000763 def test_set_nonstring_types(self):
764 cf = self.newconfig()
765 cf.add_section('non-string')
766 cf.set('non-string', 'int', 1)
767 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
768 cf.set('non-string', 'dict', {'pi': 3.14159})
769 self.assertEqual(cf.get('non-string', 'int'), 1)
770 self.assertEqual(cf.get('non-string', 'list'),
771 [0, 1, 1, 2, 3, 5, 8, 13])
772 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000773
Georg Brandl96a60ae2010-07-28 13:13:46 +0000774class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
775 delimiters = (':=', '$')
776 comment_prefixes = ('//', '"')
777
778class RawConfigParserTestSambaConf(BasicTestCase):
779 config_class = configparser.RawConfigParser
780 comment_prefixes = ('#', ';', '//', '----')
781 empty_lines_in_values = False
782
783 def test_reading(self):
784 smbconf = support.findfile("cfgparser.2")
785 # check when we pass a mix of readable and non-readable files:
786 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000787 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000788 self.assertEqual(parsed_files, [smbconf])
789 sections = ['global', 'homes', 'printers',
790 'print$', 'pdf-generator', 'tmp', 'Agustin']
791 self.assertEqual(cf.sections(), sections)
792 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
793 self.assertEqual(cf.getint("global", "max log size"), 50)
794 self.assertEqual(cf.get("global", "hosts allow"), "127.")
795 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000796
Fred Drake0eebd5c2002-10-25 21:52:00 +0000797class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000798 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000799
800 def test_safe_interpolation(self):
801 # See http://www.python.org/sf/511737
802 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000803 "option1{eq}xxx\n"
804 "option2{eq}%(option1)s/xxx\n"
805 "ok{eq}%(option1)s/%%s\n"
806 "not_ok{eq}%(option2)s/%%s".format(
807 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000808 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
809 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
810
Guido van Rossumd8faa362007-04-27 19:54:29 +0000811 def test_set_malformatted_interpolation(self):
812 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000813 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000814
815 self.assertEqual(cf.get('sect', "option1"), "foo")
816
817 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
818 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
819 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
820
821 self.assertEqual(cf.get('sect', "option1"), "foo")
822
Georg Brandl1f9fa312009-04-27 16:42:58 +0000823 # bug #5741: double percents are *not* malformed
824 cf.set("sect", "option2", "foo%%bar")
825 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
826
David Goodger1cbf2062004-10-03 15:55:09 +0000827 def test_set_nonstring_types(self):
828 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000829 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000830 # Check that we get a TypeError when setting non-string values
831 # in an existing section:
832 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
833 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
834 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
835 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
836 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
837 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
838
Łukasz Langac264c092010-11-20 16:15:37 +0000839 def test_add_section_default(self):
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000840 cf = self.newconfig()
Łukasz Langac264c092010-11-20 16:15:37 +0000841 self.assertRaises(ValueError, cf.add_section, self.default_section)
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000842
Georg Brandl96a60ae2010-07-28 13:13:46 +0000843class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
844 delimiters = (':=', '$')
845 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000846
847class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
848 allow_no_value = True
849
Georg Brandl8dcaa732010-07-29 12:17:40 +0000850class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
851 config_class = configparser.SafeConfigParser
852 delimiters = {'='}
853 comment_prefixes = {'#'}
854 allow_no_value = True
855
856 def test_cfgparser_dot_3(self):
857 tricky = support.findfile("cfgparser.3")
858 cf = self.newconfig()
859 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
860 self.assertEqual(cf.sections(), ['strange',
861 'corruption',
862 'yeah, sections can be '
863 'indented as well',
864 'another one!',
865 'no values here',
866 'tricky interpolation',
867 'more interpolation'])
Łukasz Langac264c092010-11-20 16:15:37 +0000868 self.assertEqual(cf.getint(self.default_section, 'go',
Fred Drakecc645b92010-09-04 04:35:34 +0000869 vars={'interpolate': '-1'}), -1)
870 with self.assertRaises(ValueError):
871 # no interpolation will happen
Łukasz Langac264c092010-11-20 16:15:37 +0000872 cf.getint(self.default_section, 'go', raw=True,
873 vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000874 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
875 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
876 longname = 'yeah, sections can be indented as well'
877 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000878 self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000879 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
880 # `go` from DEFAULT
881 with self.assertRaises(configparser.InterpolationMissingOptionError):
882 cf.items('no values here')
883 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
884 self.assertEqual(cf.get('tricky interpolation', 'lets'),
885 cf.get('tricky interpolation', 'go'))
886 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
887
888 def test_unicode_failure(self):
889 tricky = support.findfile("cfgparser.3")
890 cf = self.newconfig()
891 with self.assertRaises(UnicodeDecodeError):
892 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000893
Fred Drake88444412010-09-03 04:22:36 +0000894
895class Issue7005TestCase(unittest.TestCase):
896 """Test output when None is set() as a value and allow_no_value == False.
897
898 http://bugs.python.org/issue7005
899
900 """
901
902 expected_output = "[section]\noption = None\n\n"
903
904 def prepare(self, config_class):
905 # This is the default, but that's the point.
906 cp = config_class(allow_no_value=False)
907 cp.add_section("section")
908 cp.set("section", "option", None)
909 sio = io.StringIO()
910 cp.write(sio)
911 return sio.getvalue()
912
913 def test_none_as_value_stringified(self):
914 output = self.prepare(configparser.ConfigParser)
915 self.assertEqual(output, self.expected_output)
916
917 def test_none_as_value_stringified_raw(self):
918 output = self.prepare(configparser.RawConfigParser)
919 self.assertEqual(output, self.expected_output)
920
921
Thomas Wouters89f507f2006-12-13 04:49:30 +0000922class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000923 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000924
925 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +0000926 cf = self.fromstring("[b]\n"
927 "o4=1\n"
928 "o3=2\n"
929 "o2=3\n"
930 "o1=4\n"
931 "[a]\n"
932 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000933 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +0000934 cf.write(output)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000935 self.assertEqual(output.getvalue(),
936 "[a]\n"
937 "k = v\n\n"
938 "[b]\n"
939 "o1 = 4\n"
940 "o2 = 3\n"
941 "o3 = 2\n"
942 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000943
Fred Drake03c44a32010-02-19 06:08:41 +0000944
Georg Brandl96a60ae2010-07-28 13:13:46 +0000945class CompatibleTestCase(CfgParserTestCaseClass):
946 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +0000947 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +0000948
949 def test_comment_handling(self):
950 config_string = textwrap.dedent("""\
951 [Commented Bar]
952 baz=qwe ; a comment
953 foo: bar # not a comment!
954 # but this is a comment
955 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000956 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +0000957 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +0000958 """)
959 cf = self.fromstring(config_string)
960 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
961 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000962 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000963
964
Fred Drakec6f28912002-10-25 19:40:49 +0000965def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000966 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000967 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000968 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000969 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000970 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000971 RawConfigParserTestCaseNonStandardDelimiters,
972 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000973 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000974 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000975 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000976 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000977 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +0000978 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +0000979 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000980 CompatibleTestCase,
Łukasz Langac264c092010-11-20 16:15:37 +0000981 ConfigParserTestCaseNonStandardDefaultSection,
Fred Drake03c44a32010-02-19 06:08:41 +0000982 )
983
Fred Drake3af0eb82002-10-25 18:09:24 +0000984
Fred Drakec6f28912002-10-25 19:40:49 +0000985if __name__ == "__main__":
986 test_main()