blob: efa12339123e4760d6be86940b55bf72678d60d3 [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
149 # API access
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000150 self.assertNotIn('__name__', cf.options("Foo Bar"),
151 '__name__ "option" should not be exposed by the API!')
Fred Drakec6f28912002-10-25 19:40:49 +0000152
Łukasz Langa26d513c2010-11-10 18:57:39 +0000153 # mapping access
154 self.assertNotIn('__name__', cf['Foo Bar'],
155 '__name__ "option" should not be exposed by '
156 'mapping protocol access')
157 self.assertFalse('__name__' in cf['Foo Bar'])
158 with self.assertRaises(ValueError):
159 cf['Foo Bar']['__name__']
160 with self.assertRaises(ValueError):
161 del cf['Foo Bar']['__name__']
162 with self.assertRaises(ValueError):
163 cf['Foo Bar']['__name__'] = "can't write to this special name"
164
Fred Drakec6f28912002-10-25 19:40:49 +0000165 # Make sure the right things happen for remove_option();
166 # added to include check for SourceForge bug #123324:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000167
168 # API acceess
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000169 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000170 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000171 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000172 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000173 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000174 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000175 " that was removed")
176
Michael Foordbd6c0792010-07-25 23:09:25 +0000177 with self.assertRaises(configparser.NoSectionError) as cm:
178 cf.remove_option('No Such Section', 'foo')
179 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000180
181 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000182 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000183
Łukasz Langa26d513c2010-11-10 18:57:39 +0000184 # mapping access
185 del cf['Spacey Bar']['foo']
186 self.assertFalse('foo' in cf['Spacey Bar'])
187 with self.assertRaises(KeyError):
188 del cf['Spacey Bar']['foo']
189 with self.assertRaises(KeyError):
190 del cf['No Such Section']['foo']
191
Fred Drakea4923622010-08-09 12:52:45 +0000192 def test_basic(self):
193 config_string = """\
194[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000195foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000196[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000197foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000198[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000199 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000200 baz {0[0]} qwe
201[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000202foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000203baz{0[0]}qwe {1[0]}another one
204[Long Line]
205foo{0[1]} this line is much, much longer than my editor
206 likes it.
207[Section\\with$weird%characters[\t]
208[Internationalized Stuff]
209foo[bg]{0[1]} Bulgarian
210foo{0[0]}Default
211foo[en]{0[0]}English
212foo[de]{0[0]}Deutsch
213[Spaces]
214key with spaces {0[1]} value
215another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000216[Types]
217int {0[1]} 42
218float {0[0]} 0.44
219boolean {0[0]} NO
Fred Drakea4923622010-08-09 12:52:45 +0000220""".format(self.delimiters, self.comment_prefixes)
221 if self.allow_no_value:
222 config_string += (
223 "[NoValue]\n"
224 "option-without-value\n"
225 )
226 cf = self.fromstring(config_string)
227 self.basic_test(cf)
228 if self.strict:
229 with self.assertRaises(configparser.DuplicateOptionError):
230 cf.read_string(textwrap.dedent("""\
231 [Duplicate Options Here]
232 option {0[0]} with a value
233 option {0[1]} with another value
234 """.format(self.delimiters)))
235 with self.assertRaises(configparser.DuplicateSectionError):
236 cf.read_string(textwrap.dedent("""\
237 [And Now For Something]
238 completely different {0[0]} True
239 [And Now For Something]
240 the larch {0[1]} 1
241 """.format(self.delimiters)))
242 else:
243 cf.read_string(textwrap.dedent("""\
244 [Duplicate Options Here]
245 option {0[0]} with a value
246 option {0[1]} with another value
247 """.format(self.delimiters)))
248
249 cf.read_string(textwrap.dedent("""\
250 [And Now For Something]
251 completely different {0[0]} True
252 [And Now For Something]
253 the larch {0[1]} 1
254 """.format(self.delimiters)))
255
256 def test_basic_from_dict(self):
257 config = {
258 "Foo Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000259 "foo": "bar1",
Fred Drakea4923622010-08-09 12:52:45 +0000260 },
261 "Spacey Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000262 "foo": "bar2",
Fred Drakea4923622010-08-09 12:52:45 +0000263 },
264 "Spacey Bar From The Beginning": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000265 "foo": "bar3",
Fred Drakea4923622010-08-09 12:52:45 +0000266 "baz": "qwe",
267 },
268 "Commented Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000269 "foo": "bar4",
Fred Drakea4923622010-08-09 12:52:45 +0000270 "baz": "qwe",
271 },
272 "Long Line": {
273 "foo": "this line is much, much longer than my editor\nlikes "
274 "it.",
275 },
276 "Section\\with$weird%characters[\t": {
277 },
278 "Internationalized Stuff": {
279 "foo[bg]": "Bulgarian",
280 "foo": "Default",
281 "foo[en]": "English",
282 "foo[de]": "Deutsch",
283 },
284 "Spaces": {
285 "key with spaces": "value",
286 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000287 },
288 "Types": {
289 "int": 42,
290 "float": 0.44,
291 "boolean": False,
292 },
Fred Drakea4923622010-08-09 12:52:45 +0000293 }
294 if self.allow_no_value:
295 config.update({
296 "NoValue": {
297 "option-without-value": None,
298 }
299 })
300 cf = self.newconfig()
301 cf.read_dict(config)
302 self.basic_test(cf)
303 if self.strict:
304 with self.assertRaises(configparser.DuplicateOptionError):
305 cf.read_dict({
306 "Duplicate Options Here": {
307 'option': 'with a value',
308 'OPTION': 'with another value',
309 },
310 })
311 else:
312 cf.read_dict({
313 "Duplicate Options Here": {
314 'option': 'with a value',
315 'OPTION': 'with another value',
316 },
317 })
318
319
Fred Drakec6f28912002-10-25 19:40:49 +0000320 def test_case_sensitivity(self):
321 cf = self.newconfig()
322 cf.add_section("A")
323 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000324 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000325 L = cf.sections()
326 L.sort()
327 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000328 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000329 cf.set("a", "B", "value")
330 eq(cf.options("a"), ["b"])
331 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000332 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000333 with self.assertRaises(configparser.NoSectionError):
334 # section names are case-sensitive
335 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000336 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000337 cf.set("A", "A-B", "A-B value")
338 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000339 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000340 cf.has_option("A", opt),
341 "has_option() returned false for option which should exist")
342 eq(cf.options("A"), ["a-b"])
343 eq(cf.options("a"), ["b"])
344 cf.remove_option("a", "B")
345 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000346
Fred Drakec6f28912002-10-25 19:40:49 +0000347 # SF bug #432369:
348 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000349 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000350 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000351 eq(cf.options("MySection"), ["option"])
352 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000353
Fred Drakec6f28912002-10-25 19:40:49 +0000354 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000355 cf = self.fromstring("[section]\n"
356 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000357 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000358 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000359
Fred Drake3c823aa2001-02-26 21:55:34 +0000360
Łukasz Langa26d513c2010-11-10 18:57:39 +0000361 def test_case_sensitivity_mapping_access(self):
362 cf = self.newconfig()
363 cf["A"] = {}
364 cf["a"] = {"B": "value"}
365 cf["B"] = {}
366 L = [section for section in cf]
367 L.sort()
368 eq = self.assertEqual
369 elem_eq = self.assertItemsEqual
Łukasz Langac264c092010-11-20 16:15:37 +0000370 eq(L, sorted(["A", "B", self.default_section, "a"]))
Łukasz Langa26d513c2010-11-10 18:57:39 +0000371 eq(cf["a"].keys(), {"b"})
372 eq(cf["a"]["b"], "value",
373 "could not locate option, expecting case-insensitive option names")
374 with self.assertRaises(KeyError):
375 # section names are case-sensitive
376 cf["b"]["A"] = "value"
377 self.assertTrue("b" in cf["a"])
378 cf["A"]["A-B"] = "A-B value"
379 for opt in ("a-b", "A-b", "a-B", "A-B"):
380 self.assertTrue(
381 opt in cf["A"],
382 "has_option() returned false for option which should exist")
383 eq(cf["A"].keys(), {"a-b"})
384 eq(cf["a"].keys(), {"b"})
385 del cf["a"]["B"]
386 elem_eq(cf["a"].keys(), {})
387
388 # SF bug #432369:
389 cf = self.fromstring(
390 "[MySection]\nOption{} first line \n\tsecond line \n".format(
391 self.delimiters[0]))
392 eq(cf["MySection"].keys(), {"option"})
393 eq(cf["MySection"]["Option"], "first line\nsecond line")
394
395 # SF bug #561822:
396 cf = self.fromstring("[section]\n"
397 "nekey{}nevalue\n".format(self.delimiters[0]),
398 defaults={"key":"value"})
399 self.assertTrue("Key" in cf["section"])
400
David Goodger68a1abd2004-10-03 15:40:25 +0000401 def test_default_case_sensitivity(self):
402 cf = self.newconfig({"foo": "Bar"})
403 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000404 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000405 "could not locate option, expecting case-insensitive option names")
406 cf = self.newconfig({"Foo": "Bar"})
407 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000408 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000409 "could not locate option, expecting case-insensitive defaults")
410
Fred Drakec6f28912002-10-25 19:40:49 +0000411 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000412 cf = self.newconfig()
413 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000414 "[Foo]\n"
415 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000416 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000417 "[Foo]\n"
418 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000419 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000420 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000421 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000422 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000423 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000424 "[Foo]\n wrong-indent\n")
425 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000426 # read_file on a real file
427 tricky = support.findfile("cfgparser.3")
428 if self.delimiters[0] == '=':
429 error = configparser.ParsingError
430 expected = (tricky,)
431 else:
432 error = configparser.MissingSectionHeaderError
433 expected = (tricky, 1,
434 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000435 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000436 e = self.parse_error(cf, error, f)
437 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000438
Fred Drakea4923622010-08-09 12:52:45 +0000439 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000440 if hasattr(src, 'readline'):
441 sio = src
442 else:
443 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000444 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000445 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000446 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000447
Fred Drakec6f28912002-10-25 19:40:49 +0000448 def test_query_errors(self):
449 cf = self.newconfig()
450 self.assertEqual(cf.sections(), [],
451 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000452 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000453 "new ConfigParser should have no acknowledged "
454 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000455 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000456 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000457 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000458 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000459 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000460 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000461 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000462 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000463 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000464
Fred Drakea4923622010-08-09 12:52:45 +0000465 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000466 try:
Fred Drakea4923622010-08-09 12:52:45 +0000467 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000468 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000469 return e
470 else:
471 self.fail("expected exception type %s.%s"
472 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000473
Fred Drakec6f28912002-10-25 19:40:49 +0000474 def test_boolean(self):
475 cf = self.fromstring(
476 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000477 "T1{equals}1\n"
478 "T2{equals}TRUE\n"
479 "T3{equals}True\n"
480 "T4{equals}oN\n"
481 "T5{equals}yes\n"
482 "F1{equals}0\n"
483 "F2{equals}FALSE\n"
484 "F3{equals}False\n"
485 "F4{equals}oFF\n"
486 "F5{equals}nO\n"
487 "E1{equals}2\n"
488 "E2{equals}foo\n"
489 "E3{equals}-1\n"
490 "E4{equals}0.1\n"
491 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000492 )
493 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000494 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
495 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000496 self.assertRaises(ValueError,
497 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000498
Fred Drakec6f28912002-10-25 19:40:49 +0000499 def test_weird_errors(self):
500 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000501 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000502 with self.assertRaises(configparser.DuplicateSectionError) as cm:
503 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000504 e = cm.exception
505 self.assertEqual(str(e), "Section 'Foo' already exists")
506 self.assertEqual(e.args, ("Foo", None, None))
507
508 if self.strict:
509 with self.assertRaises(configparser.DuplicateSectionError) as cm:
510 cf.read_string(textwrap.dedent("""\
511 [Foo]
512 will this be added{equals}True
513 [Bar]
514 what about this{equals}True
515 [Foo]
516 oops{equals}this won't
517 """.format(equals=self.delimiters[0])), source='<foo-bar>')
518 e = cm.exception
519 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
520 "section 'Foo' already exists")
521 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
522
523 with self.assertRaises(configparser.DuplicateOptionError) as cm:
524 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
525 e = cm.exception
526 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
527 "in section 'Bar' already exists")
528 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000529
530 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000531 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000532 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000533 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000534 " likes it.\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000535 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000536 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000537 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000538 "[Long Line - With Comments!]\n"
539 "test {0[1]} we {comment} can\n"
540 " also {comment} place\n"
541 " comments {comment} in\n"
542 " multiline {comment} values"
Łukasz Langac264c092010-11-20 16:15:37 +0000543 "\n".format(self.delimiters, comment=self.comment_prefixes[0],
544 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000545 )
Fred Drake03c44a32010-02-19 06:08:41 +0000546 if self.allow_no_value:
547 config_string += (
548 "[Valueless]\n"
549 "option-without-value\n"
550 )
551
552 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000553 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000554 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000555 expect_string = (
Łukasz Langac264c092010-11-20 16:15:37 +0000556 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000557 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000558 "\tlong line\n"
559 "\n"
560 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000561 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000562 "\tlikes it.\n"
563 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000564 "[Long Line - With Comments!]\n"
565 "test {equals} we\n"
566 "\talso\n"
567 "\tcomments\n"
568 "\tmultiline\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000569 "\n".format(equals=self.delimiters[0],
570 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000571 )
Fred Drake03c44a32010-02-19 06:08:41 +0000572 if self.allow_no_value:
573 expect_string += (
574 "[Valueless]\n"
575 "option-without-value\n"
576 "\n"
577 )
578 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000579
Fred Drakeabc086f2004-05-18 03:29:52 +0000580 def test_set_string_types(self):
581 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000582 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000583 # Check that we don't get an exception when setting values in
584 # an existing section using strings:
585 class mystr(str):
586 pass
587 cf.set("sect", "option1", "splat")
588 cf.set("sect", "option1", mystr("splat"))
589 cf.set("sect", "option2", "splat")
590 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000591 cf.set("sect", "option1", "splat")
592 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000593
Fred Drake82903142004-05-18 04:24:02 +0000594 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000595 if self.delimiters[0] != '=':
596 # skip reading the file if we're using an incompatible format
597 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000598 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000599 # check when we pass a mix of readable and non-readable files:
600 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000601 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000602 self.assertEqual(parsed_files, [file1])
603 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
604 # check when we pass only a filename:
605 cf = self.newconfig()
606 parsed_files = cf.read(file1)
607 self.assertEqual(parsed_files, [file1])
608 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
609 # check when we pass only missing files:
610 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000611 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000612 self.assertEqual(parsed_files, [])
613 # check when we pass no files:
614 cf = self.newconfig()
615 parsed_files = cf.read([])
616 self.assertEqual(parsed_files, [])
617
Fred Drakec6f28912002-10-25 19:40:49 +0000618 # shared by subclasses
619 def get_interpolation_config(self):
620 return self.fromstring(
621 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000622 "bar{equals}something %(with1)s interpolation (1 step)\n"
623 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
624 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
625 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
626 "with11{equals}%(with10)s\n"
627 "with10{equals}%(with9)s\n"
628 "with9{equals}%(with8)s\n"
629 "with8{equals}%(With7)s\n"
630 "with7{equals}%(WITH6)s\n"
631 "with6{equals}%(with5)s\n"
632 "With5{equals}%(with4)s\n"
633 "WITH4{equals}%(with3)s\n"
634 "with3{equals}%(with2)s\n"
635 "with2{equals}%(with1)s\n"
636 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000637 "\n"
638 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000639 "foo{equals}%(bar)s\n"
640 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000641 "\n"
642 "[Interpolation Error]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000643 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]),
Fred Drake54782192002-12-31 06:57:25 +0000644 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000645 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000646
Fred Drake98e3b292002-10-25 20:42:44 +0000647 def check_items_config(self, expected):
648 cf = self.fromstring(
649 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000650 "name {0[0]} value\n"
651 "key{0[1]} |%(name)s| \n"
652 "getdefault{0[1]} |%(default)s|\n"
653 "getname{0[1]} |%(__name__)s|".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000654 defaults={"default": "<default>"})
655 L = list(cf.items("section"))
656 L.sort()
657 self.assertEqual(L, expected)
658
Fred Drake8ef67672000-09-27 22:45:25 +0000659
Fred Drakea4923622010-08-09 12:52:45 +0000660class StrictTestCase(BasicTestCase):
661 config_class = configparser.RawConfigParser
662 strict = True
663
664
Georg Brandl96a60ae2010-07-28 13:13:46 +0000665class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000666 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000667
668 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000669 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000670 configparser.ConfigParser: ("something %(with11)s "
671 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000672 configparser.SafeConfigParser: "%(with1)s",
673 }
Fred Drakec6f28912002-10-25 19:40:49 +0000674 cf = self.get_interpolation_config()
675 eq = self.assertEqual
676 eq(cf.get("Foo", "getname"), "Foo")
677 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
678 eq(cf.get("Foo", "bar9"),
679 "something with lots of interpolation (9 steps)")
680 eq(cf.get("Foo", "bar10"),
681 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000682 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000683 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000684
Fred Drake54782192002-12-31 06:57:25 +0000685 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000686 rawval = {
687 configparser.ConfigParser: '%(reference)s',
688 configparser.SafeConfigParser: '',
689 }
Fred Drakea4923622010-08-09 12:52:45 +0000690 cf = self.get_interpolation_config()
691 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000692 "Interpolation Error", "name")
693 self.assertEqual(e.reference, "reference")
694 self.assertEqual(e.section, "Interpolation Error")
695 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000696 self.assertEqual(e.args, ('name', 'Interpolation Error',
697 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000698
Fred Drake98e3b292002-10-25 20:42:44 +0000699 def test_items(self):
700 self.check_items_config([('default', '<default>'),
701 ('getdefault', '|<default>|'),
702 ('getname', '|section|'),
703 ('key', '|value|'),
704 ('name', 'value')])
705
David Goodger1cbf2062004-10-03 15:55:09 +0000706 def test_set_nonstring_types(self):
707 cf = self.newconfig()
708 cf.add_section('non-string')
709 cf.set('non-string', 'int', 1)
710 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
711 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
712 '%(list)': '%(list)'})
713 cf.set('non-string', 'string_with_interpolation', '%(list)s')
714 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
715 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
716 self.assertEqual(cf.get('non-string', 'list', raw=True),
717 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
718 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
719 self.assertEqual(cf.get('non-string', 'dict', raw=True),
720 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
721 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
722 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
723 raw=True), '%(list)s')
724 self.assertRaises(ValueError, cf.get, 'non-string',
725 'string_with_interpolation', raw=False)
726
Georg Brandl96a60ae2010-07-28 13:13:46 +0000727class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
728 delimiters = (':=', '$')
729 comment_prefixes = ('//', '"')
730
Łukasz Langac264c092010-11-20 16:15:37 +0000731class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
732 default_section = 'general'
733
Georg Brandl96a60ae2010-07-28 13:13:46 +0000734class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000735 config_class = configparser.ConfigParser
736 wonderful_spam = ("I'm having spam spam spam spam "
737 "spam spam spam beaked beans spam "
738 "spam spam and spam!").replace(' ', '\t\n')
739
740 def setUp(self):
741 cf = self.newconfig()
742 for i in range(100):
743 s = 'section{}'.format(i)
744 cf.add_section(s)
745 for j in range(10):
746 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
747 with open(support.TESTFN, 'w') as f:
748 cf.write(f)
749
750 def tearDown(self):
751 os.unlink(support.TESTFN)
752
753 def test_dominating_multiline_values(self):
754 # We're reading from file because this is where the code changed
755 # during performance updates in Python 3.2
756 cf_from_file = self.newconfig()
757 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000758 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000759 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
760 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000761
Georg Brandl96a60ae2010-07-28 13:13:46 +0000762class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000763 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000764
765 def test_interpolation(self):
766 cf = self.get_interpolation_config()
767 eq = self.assertEqual
768 eq(cf.get("Foo", "getname"), "%(__name__)s")
769 eq(cf.get("Foo", "bar"),
770 "something %(with1)s interpolation (1 step)")
771 eq(cf.get("Foo", "bar9"),
772 "something %(with9)s lots of interpolation (9 steps)")
773 eq(cf.get("Foo", "bar10"),
774 "something %(with10)s lots of interpolation (10 steps)")
775 eq(cf.get("Foo", "bar11"),
776 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000777
Fred Drake98e3b292002-10-25 20:42:44 +0000778 def test_items(self):
779 self.check_items_config([('default', '<default>'),
780 ('getdefault', '|%(default)s|'),
781 ('getname', '|%(__name__)s|'),
782 ('key', '|%(name)s|'),
783 ('name', 'value')])
784
David Goodger1cbf2062004-10-03 15:55:09 +0000785 def test_set_nonstring_types(self):
786 cf = self.newconfig()
787 cf.add_section('non-string')
788 cf.set('non-string', 'int', 1)
789 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
790 cf.set('non-string', 'dict', {'pi': 3.14159})
791 self.assertEqual(cf.get('non-string', 'int'), 1)
792 self.assertEqual(cf.get('non-string', 'list'),
793 [0, 1, 1, 2, 3, 5, 8, 13])
794 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000795
Georg Brandl96a60ae2010-07-28 13:13:46 +0000796class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
797 delimiters = (':=', '$')
798 comment_prefixes = ('//', '"')
799
800class RawConfigParserTestSambaConf(BasicTestCase):
801 config_class = configparser.RawConfigParser
802 comment_prefixes = ('#', ';', '//', '----')
803 empty_lines_in_values = False
804
805 def test_reading(self):
806 smbconf = support.findfile("cfgparser.2")
807 # check when we pass a mix of readable and non-readable files:
808 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000809 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000810 self.assertEqual(parsed_files, [smbconf])
811 sections = ['global', 'homes', 'printers',
812 'print$', 'pdf-generator', 'tmp', 'Agustin']
813 self.assertEqual(cf.sections(), sections)
814 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
815 self.assertEqual(cf.getint("global", "max log size"), 50)
816 self.assertEqual(cf.get("global", "hosts allow"), "127.")
817 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000818
Fred Drake0eebd5c2002-10-25 21:52:00 +0000819class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000820 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000821
822 def test_safe_interpolation(self):
823 # See http://www.python.org/sf/511737
824 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000825 "option1{eq}xxx\n"
826 "option2{eq}%(option1)s/xxx\n"
827 "ok{eq}%(option1)s/%%s\n"
828 "not_ok{eq}%(option2)s/%%s".format(
829 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000830 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
831 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
832
Guido van Rossumd8faa362007-04-27 19:54:29 +0000833 def test_set_malformatted_interpolation(self):
834 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000835 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000836
837 self.assertEqual(cf.get('sect', "option1"), "foo")
838
839 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
840 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
841 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
842
843 self.assertEqual(cf.get('sect', "option1"), "foo")
844
Georg Brandl1f9fa312009-04-27 16:42:58 +0000845 # bug #5741: double percents are *not* malformed
846 cf.set("sect", "option2", "foo%%bar")
847 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
848
David Goodger1cbf2062004-10-03 15:55:09 +0000849 def test_set_nonstring_types(self):
850 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000851 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000852 # Check that we get a TypeError when setting non-string values
853 # in an existing section:
854 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
855 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
856 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
857 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
858 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
859 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
860
Łukasz Langac264c092010-11-20 16:15:37 +0000861 def test_add_section_default(self):
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000862 cf = self.newconfig()
Łukasz Langac264c092010-11-20 16:15:37 +0000863 self.assertRaises(ValueError, cf.add_section, self.default_section)
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000864
Georg Brandl96a60ae2010-07-28 13:13:46 +0000865class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
866 delimiters = (':=', '$')
867 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000868
869class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
870 allow_no_value = True
871
Georg Brandl8dcaa732010-07-29 12:17:40 +0000872class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
873 config_class = configparser.SafeConfigParser
874 delimiters = {'='}
875 comment_prefixes = {'#'}
876 allow_no_value = True
877
878 def test_cfgparser_dot_3(self):
879 tricky = support.findfile("cfgparser.3")
880 cf = self.newconfig()
881 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
882 self.assertEqual(cf.sections(), ['strange',
883 'corruption',
884 'yeah, sections can be '
885 'indented as well',
886 'another one!',
887 'no values here',
888 'tricky interpolation',
889 'more interpolation'])
Łukasz Langac264c092010-11-20 16:15:37 +0000890 self.assertEqual(cf.getint(self.default_section, 'go',
Fred Drakecc645b92010-09-04 04:35:34 +0000891 vars={'interpolate': '-1'}), -1)
892 with self.assertRaises(ValueError):
893 # no interpolation will happen
Łukasz Langac264c092010-11-20 16:15:37 +0000894 cf.getint(self.default_section, 'go', raw=True,
895 vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000896 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
897 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
898 longname = 'yeah, sections can be indented as well'
899 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
900 self.assertEquals(cf.get(longname, 'lets use some Unicode'),
901 '片仮名')
902 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
903 # `go` from DEFAULT
904 with self.assertRaises(configparser.InterpolationMissingOptionError):
905 cf.items('no values here')
906 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
907 self.assertEqual(cf.get('tricky interpolation', 'lets'),
908 cf.get('tricky interpolation', 'go'))
909 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
910
911 def test_unicode_failure(self):
912 tricky = support.findfile("cfgparser.3")
913 cf = self.newconfig()
914 with self.assertRaises(UnicodeDecodeError):
915 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000916
Fred Drake88444412010-09-03 04:22:36 +0000917
918class Issue7005TestCase(unittest.TestCase):
919 """Test output when None is set() as a value and allow_no_value == False.
920
921 http://bugs.python.org/issue7005
922
923 """
924
925 expected_output = "[section]\noption = None\n\n"
926
927 def prepare(self, config_class):
928 # This is the default, but that's the point.
929 cp = config_class(allow_no_value=False)
930 cp.add_section("section")
931 cp.set("section", "option", None)
932 sio = io.StringIO()
933 cp.write(sio)
934 return sio.getvalue()
935
936 def test_none_as_value_stringified(self):
937 output = self.prepare(configparser.ConfigParser)
938 self.assertEqual(output, self.expected_output)
939
940 def test_none_as_value_stringified_raw(self):
941 output = self.prepare(configparser.RawConfigParser)
942 self.assertEqual(output, self.expected_output)
943
944
Thomas Wouters89f507f2006-12-13 04:49:30 +0000945class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000946 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000947
948 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +0000949 cf = self.fromstring("[b]\n"
950 "o4=1\n"
951 "o3=2\n"
952 "o2=3\n"
953 "o1=4\n"
954 "[a]\n"
955 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000956 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +0000957 cf.write(output)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000958 self.assertEquals(output.getvalue(),
959 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000960 "k = v\n\n"
Thomas Wouters89f507f2006-12-13 04:49:30 +0000961 "[b]\n"
962 "o1 = 4\n"
963 "o2 = 3\n"
964 "o3 = 2\n"
965 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000966
Fred Drake03c44a32010-02-19 06:08:41 +0000967
Georg Brandl96a60ae2010-07-28 13:13:46 +0000968class CompatibleTestCase(CfgParserTestCaseClass):
969 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +0000970 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +0000971
972 def test_comment_handling(self):
973 config_string = textwrap.dedent("""\
974 [Commented Bar]
975 baz=qwe ; a comment
976 foo: bar # not a comment!
977 # but this is a comment
978 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000979 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +0000980 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +0000981 """)
982 cf = self.fromstring(config_string)
983 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
984 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000985 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000986
987
Fred Drakec6f28912002-10-25 19:40:49 +0000988def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000989 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000990 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000991 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000992 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000993 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000994 RawConfigParserTestCaseNonStandardDelimiters,
995 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000996 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000997 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000998 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000999 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001000 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +00001001 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +00001002 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001003 CompatibleTestCase,
Łukasz Langac264c092010-11-20 16:15:37 +00001004 ConfigParserTestCaseNonStandardDefaultSection,
Fred Drake03c44a32010-02-19 06:08:41 +00001005 )
1006
Fred Drake3af0eb82002-10-25 18:09:24 +00001007
Fred Drakec6f28912002-10-25 19:40:49 +00001008if __name__ == "__main__":
1009 test_main()