blob: 2ea80dcd6c3ba0067ad35a4847c7e15f0ced2a59 [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
Łukasz Langa535c0772010-12-04 13:48:13 +00005import sys
Georg Brandl96a60ae2010-07-28 13:13:46 +00006import textwrap
Łukasz Langa535c0772010-12-04 13:48:13 +00007import unittest
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00008import warnings
Fred Drake8ef67672000-09-27 22:45:25 +00009
Benjamin Petersonee8712c2008-05-20 21:35:26 +000010from test import support
Fred Drake3d5f7e82000-12-04 16:30:40 +000011
Raymond Hettingerf80680d2008-02-06 00:07:11 +000012class SortedDict(collections.UserDict):
Fred Drake03c44a32010-02-19 06:08:41 +000013
Thomas Wouters89f507f2006-12-13 04:49:30 +000014 def items(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000015 return sorted(self.data.items())
Thomas Wouters89f507f2006-12-13 04:49:30 +000016
17 def keys(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000018 return sorted(self.data.keys())
Thomas Wouters9fe394c2007-02-05 01:24:16 +000019
Thomas Wouters89f507f2006-12-13 04:49:30 +000020 def values(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000021 return [i[1] for i in self.items()]
Thomas Wouters89f507f2006-12-13 04:49:30 +000022
23 def iteritems(self): return iter(self.items())
24 def iterkeys(self): return iter(self.keys())
25 __iter__ = iterkeys
26 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000027
Fred Drake03c44a32010-02-19 06:08:41 +000028
Georg Brandl96a60ae2010-07-28 13:13:46 +000029class CfgParserTestCaseClass(unittest.TestCase):
Fred Drake03c44a32010-02-19 06:08:41 +000030 allow_no_value = False
Georg Brandl96a60ae2010-07-28 13:13:46 +000031 delimiters = ('=', ':')
32 comment_prefixes = (';', '#')
33 empty_lines_in_values = True
34 dict_type = configparser._default_dict
Fred Drakea4923622010-08-09 12:52:45 +000035 strict = False
Łukasz Langac264c092010-11-20 16:15:37 +000036 default_section = configparser.DEFAULTSECT
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000037 interpolation = configparser._UNSET
Fred Drake03c44a32010-02-19 06:08:41 +000038
Fred Drakec6f28912002-10-25 19:40:49 +000039 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000040 arguments = dict(
Fred Drakea4923622010-08-09 12:52:45 +000041 defaults=defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000042 allow_no_value=self.allow_no_value,
43 delimiters=self.delimiters,
44 comment_prefixes=self.comment_prefixes,
45 empty_lines_in_values=self.empty_lines_in_values,
46 dict_type=self.dict_type,
Fred Drakea4923622010-08-09 12:52:45 +000047 strict=self.strict,
Łukasz Langac264c092010-11-20 16:15:37 +000048 default_section=self.default_section,
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000049 interpolation=self.interpolation,
Georg Brandl96a60ae2010-07-28 13:13:46 +000050 )
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000051 with warnings.catch_warnings():
52 warnings.simplefilter("ignore", category=DeprecationWarning)
53 instance = self.config_class(**arguments)
54 return instance
Fred Drake8ef67672000-09-27 22:45:25 +000055
Fred Drakec6f28912002-10-25 19:40:49 +000056 def fromstring(self, string, defaults=None):
57 cf = self.newconfig(defaults)
Fred Drakea4923622010-08-09 12:52:45 +000058 cf.read_string(string)
Fred Drakec6f28912002-10-25 19:40:49 +000059 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000060
Georg Brandl96a60ae2010-07-28 13:13:46 +000061class BasicTestCase(CfgParserTestCaseClass):
62
Fred Drakea4923622010-08-09 12:52:45 +000063 def basic_test(self, cf):
Georg Brandl96a60ae2010-07-28 13:13:46 +000064 E = ['Commented Bar',
65 'Foo Bar',
66 'Internationalized Stuff',
67 'Long Line',
68 'Section\\with$weird%characters[\t',
69 'Spaces',
70 'Spacey Bar',
71 'Spacey Bar From The Beginning',
Fred Drakecc645b92010-09-04 04:35:34 +000072 'Types',
Fred Drake03c44a32010-02-19 06:08:41 +000073 ]
Łukasz Langa26d513c2010-11-10 18:57:39 +000074
Fred Drake03c44a32010-02-19 06:08:41 +000075 if self.allow_no_value:
Fred Drakecc645b92010-09-04 04:35:34 +000076 E.append('NoValue')
Fred Drake03c44a32010-02-19 06:08:41 +000077 E.sort()
Łukasz Langa26d513c2010-11-10 18:57:39 +000078
79 # API access
80 L = cf.sections()
81 L.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000082 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000083 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000084
Łukasz Langa26d513c2010-11-10 18:57:39 +000085 # mapping access
86 L = [section for section in cf]
87 L.sort()
Łukasz Langac264c092010-11-20 16:15:37 +000088 E.append(self.default_section)
Łukasz Langa26d513c2010-11-10 18:57:39 +000089 E.sort()
90 eq(L, E)
91
Fred Drakec6f28912002-10-25 19:40:49 +000092 # The use of spaces in the section names serves as a
93 # regression test for SourceForge bug #583248:
94 # http://www.python.org/sf/583248
Łukasz Langa26d513c2010-11-10 18:57:39 +000095
96 # API access
97 eq(cf.get('Foo Bar', 'foo'), 'bar1')
98 eq(cf.get('Spacey Bar', 'foo'), 'bar2')
99 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000100 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000101 eq(cf.get('Commented Bar', 'foo'), 'bar4')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000102 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +0000103 eq(cf.get('Spaces', 'key with spaces'), 'value')
104 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc645b92010-09-04 04:35:34 +0000105 eq(cf.getint('Types', 'int'), 42)
106 eq(cf.get('Types', 'int'), "42")
107 self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
108 eq(cf.get('Types', 'float'), "0.44")
109 eq(cf.getboolean('Types', 'boolean'), False)
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000110 eq(cf.get('Types', '123'), 'strange but acceptable')
Fred Drake03c44a32010-02-19 06:08:41 +0000111 if self.allow_no_value:
112 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000113
Łukasz Langa26d513c2010-11-10 18:57:39 +0000114 # test vars= and fallback=
115 eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
Fred Drakecc645b92010-09-04 04:35:34 +0000116 eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
117 with self.assertRaises(configparser.NoSectionError):
118 cf.get('No Such Foo Bar', 'foo')
119 with self.assertRaises(configparser.NoOptionError):
120 cf.get('Foo Bar', 'no-such-foo')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000121 eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
122 eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
123 eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
124 eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
125 eq(cf.getint('Types', 'int', fallback=18), 42)
126 eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
127 eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
Fred Drakecc645b92010-09-04 04:35:34 +0000128 self.assertAlmostEqual(cf.getfloat('Types', 'float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000129 fallback=0.0), 0.44)
Fred Drakecc645b92010-09-04 04:35:34 +0000130 self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000131 fallback=0.0), 0.0)
132 eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
133 eq(cf.getboolean('Types', 'boolean', fallback=True), False)
134 eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
Fred Drakecc645b92010-09-04 04:35:34 +0000135 "yes") # sic!
Łukasz Langa26d513c2010-11-10 18:57:39 +0000136 eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
137 eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
Fred Drakecc645b92010-09-04 04:35:34 +0000138 if self.allow_no_value:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000139 eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
Fred Drakecc645b92010-09-04 04:35:34 +0000140 eq(cf.get('NoValue', 'no-such-option-without-value',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000141 fallback=False), False)
Fred Drakecc645b92010-09-04 04:35:34 +0000142
Łukasz Langa26d513c2010-11-10 18:57:39 +0000143 # mapping access
144 eq(cf['Foo Bar']['foo'], 'bar1')
145 eq(cf['Spacey Bar']['foo'], 'bar2')
Łukasz Langaa73dc9d2010-11-21 13:56:42 +0000146 section = cf['Spacey Bar From The Beginning']
147 eq(section.name, 'Spacey Bar From The Beginning')
148 self.assertIs(section.parser, cf)
149 with self.assertRaises(AttributeError):
150 section.name = 'Name is read-only'
151 with self.assertRaises(AttributeError):
152 section.parser = 'Parser is read-only'
153 eq(section['foo'], 'bar3')
154 eq(section['baz'], 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000155 eq(cf['Commented Bar']['foo'], 'bar4')
156 eq(cf['Commented Bar']['baz'], 'qwe')
157 eq(cf['Spaces']['key with spaces'], 'value')
158 eq(cf['Spaces']['another with spaces'], 'splat!')
159 eq(cf['Long Line']['foo'],
160 'this line is much, much longer than my editor\nlikes it.')
161 if self.allow_no_value:
162 eq(cf['NoValue']['option-without-value'], None)
163
Fred Drakec6f28912002-10-25 19:40:49 +0000164 # Make sure the right things happen for remove_option();
165 # added to include check for SourceForge bug #123324:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000166
167 # API acceess
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000168 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000169 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000170 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000171 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000172 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000173 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000174 " that was removed")
175
Michael Foordbd6c0792010-07-25 23:09:25 +0000176 with self.assertRaises(configparser.NoSectionError) as cm:
177 cf.remove_option('No Such Section', 'foo')
178 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000179
180 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000181 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000182
Łukasz Langa26d513c2010-11-10 18:57:39 +0000183 # mapping access
184 del cf['Spacey Bar']['foo']
185 self.assertFalse('foo' in cf['Spacey Bar'])
186 with self.assertRaises(KeyError):
187 del cf['Spacey Bar']['foo']
188 with self.assertRaises(KeyError):
189 del cf['No Such Section']['foo']
190
Fred Drakea4923622010-08-09 12:52:45 +0000191 def test_basic(self):
192 config_string = """\
193[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000194foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000195[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000196foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000197[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000198 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000199 baz {0[0]} qwe
200[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000201foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000202baz{0[0]}qwe {1[0]}another one
203[Long Line]
204foo{0[1]} this line is much, much longer than my editor
205 likes it.
206[Section\\with$weird%characters[\t]
207[Internationalized Stuff]
208foo[bg]{0[1]} Bulgarian
209foo{0[0]}Default
210foo[en]{0[0]}English
211foo[de]{0[0]}Deutsch
212[Spaces]
213key with spaces {0[1]} value
214another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000215[Types]
216int {0[1]} 42
217float {0[0]} 0.44
218boolean {0[0]} NO
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000219123 {0[1]} strange but acceptable
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,
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000292 123: "strange but acceptable",
Fred Drakecc645b92010-09-04 04:35:34 +0000293 },
Fred Drakea4923622010-08-09 12:52:45 +0000294 }
295 if self.allow_no_value:
296 config.update({
297 "NoValue": {
298 "option-without-value": None,
299 }
300 })
301 cf = self.newconfig()
302 cf.read_dict(config)
303 self.basic_test(cf)
304 if self.strict:
305 with self.assertRaises(configparser.DuplicateOptionError):
306 cf.read_dict({
307 "Duplicate Options Here": {
308 'option': 'with a value',
309 'OPTION': 'with another value',
310 },
311 })
312 else:
313 cf.read_dict({
314 "Duplicate Options Here": {
315 'option': 'with a value',
316 'OPTION': 'with another value',
317 },
318 })
319
320
Fred Drakec6f28912002-10-25 19:40:49 +0000321 def test_case_sensitivity(self):
322 cf = self.newconfig()
323 cf.add_section("A")
324 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000325 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000326 L = cf.sections()
327 L.sort()
328 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000329 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000330 cf.set("a", "B", "value")
331 eq(cf.options("a"), ["b"])
332 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000333 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000334 with self.assertRaises(configparser.NoSectionError):
335 # section names are case-sensitive
336 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000337 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000338 cf.set("A", "A-B", "A-B value")
339 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000340 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000341 cf.has_option("A", opt),
342 "has_option() returned false for option which should exist")
343 eq(cf.options("A"), ["a-b"])
344 eq(cf.options("a"), ["b"])
345 cf.remove_option("a", "B")
346 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000347
Fred Drakec6f28912002-10-25 19:40:49 +0000348 # SF bug #432369:
349 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000350 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000351 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000352 eq(cf.options("MySection"), ["option"])
353 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000354
Fred Drakec6f28912002-10-25 19:40:49 +0000355 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000356 cf = self.fromstring("[section]\n"
357 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000358 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000359 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000360
Fred Drake3c823aa2001-02-26 21:55:34 +0000361
Łukasz Langa26d513c2010-11-10 18:57:39 +0000362 def test_case_sensitivity_mapping_access(self):
363 cf = self.newconfig()
364 cf["A"] = {}
365 cf["a"] = {"B": "value"}
366 cf["B"] = {}
367 L = [section for section in cf]
368 L.sort()
369 eq = self.assertEqual
Ezio Melotti263cbdf2010-11-29 02:02:10 +0000370 elem_eq = self.assertCountEqual
Łukasz Langac264c092010-11-20 16:15:37 +0000371 eq(L, sorted(["A", "B", self.default_section, "a"]))
Łukasz Langa26d513c2010-11-10 18:57:39 +0000372 eq(cf["a"].keys(), {"b"})
373 eq(cf["a"]["b"], "value",
374 "could not locate option, expecting case-insensitive option names")
375 with self.assertRaises(KeyError):
376 # section names are case-sensitive
377 cf["b"]["A"] = "value"
378 self.assertTrue("b" in cf["a"])
379 cf["A"]["A-B"] = "A-B value"
380 for opt in ("a-b", "A-b", "a-B", "A-B"):
381 self.assertTrue(
382 opt in cf["A"],
383 "has_option() returned false for option which should exist")
384 eq(cf["A"].keys(), {"a-b"})
385 eq(cf["a"].keys(), {"b"})
386 del cf["a"]["B"]
387 elem_eq(cf["a"].keys(), {})
388
389 # SF bug #432369:
390 cf = self.fromstring(
391 "[MySection]\nOption{} first line \n\tsecond line \n".format(
392 self.delimiters[0]))
393 eq(cf["MySection"].keys(), {"option"})
394 eq(cf["MySection"]["Option"], "first line\nsecond line")
395
396 # SF bug #561822:
397 cf = self.fromstring("[section]\n"
398 "nekey{}nevalue\n".format(self.delimiters[0]),
399 defaults={"key":"value"})
400 self.assertTrue("Key" in cf["section"])
401
David Goodger68a1abd2004-10-03 15:40:25 +0000402 def test_default_case_sensitivity(self):
403 cf = self.newconfig({"foo": "Bar"})
404 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000405 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000406 "could not locate option, expecting case-insensitive option names")
407 cf = self.newconfig({"Foo": "Bar"})
408 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000409 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000410 "could not locate option, expecting case-insensitive defaults")
411
Fred Drakec6f28912002-10-25 19:40:49 +0000412 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000413 cf = self.newconfig()
414 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000415 "[Foo]\n"
416 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000417 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000418 "[Foo]\n"
419 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000420 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000421 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000422 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000423 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000424 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000425 "[Foo]\n wrong-indent\n")
426 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000427 # read_file on a real file
428 tricky = support.findfile("cfgparser.3")
429 if self.delimiters[0] == '=':
430 error = configparser.ParsingError
431 expected = (tricky,)
432 else:
433 error = configparser.MissingSectionHeaderError
434 expected = (tricky, 1,
435 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000436 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000437 e = self.parse_error(cf, error, f)
438 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000439
Fred Drakea4923622010-08-09 12:52:45 +0000440 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000441 if hasattr(src, 'readline'):
442 sio = src
443 else:
444 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000445 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000446 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000447 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000448
Fred Drakec6f28912002-10-25 19:40:49 +0000449 def test_query_errors(self):
450 cf = self.newconfig()
451 self.assertEqual(cf.sections(), [],
452 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000453 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000454 "new ConfigParser should have no acknowledged "
455 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000456 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000457 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000458 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000459 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000460 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000461 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000462 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000463 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000464 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000465
Fred Drakea4923622010-08-09 12:52:45 +0000466 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000467 try:
Fred Drakea4923622010-08-09 12:52:45 +0000468 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000469 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000470 return e
471 else:
472 self.fail("expected exception type %s.%s"
473 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000474
Fred Drakec6f28912002-10-25 19:40:49 +0000475 def test_boolean(self):
476 cf = self.fromstring(
477 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000478 "T1{equals}1\n"
479 "T2{equals}TRUE\n"
480 "T3{equals}True\n"
481 "T4{equals}oN\n"
482 "T5{equals}yes\n"
483 "F1{equals}0\n"
484 "F2{equals}FALSE\n"
485 "F3{equals}False\n"
486 "F4{equals}oFF\n"
487 "F5{equals}nO\n"
488 "E1{equals}2\n"
489 "E2{equals}foo\n"
490 "E3{equals}-1\n"
491 "E4{equals}0.1\n"
492 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000493 )
494 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000495 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
496 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000497 self.assertRaises(ValueError,
498 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000499
Fred Drakec6f28912002-10-25 19:40:49 +0000500 def test_weird_errors(self):
501 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000502 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000503 with self.assertRaises(configparser.DuplicateSectionError) as cm:
504 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000505 e = cm.exception
506 self.assertEqual(str(e), "Section 'Foo' already exists")
507 self.assertEqual(e.args, ("Foo", None, None))
508
509 if self.strict:
510 with self.assertRaises(configparser.DuplicateSectionError) as cm:
511 cf.read_string(textwrap.dedent("""\
512 [Foo]
513 will this be added{equals}True
514 [Bar]
515 what about this{equals}True
516 [Foo]
517 oops{equals}this won't
518 """.format(equals=self.delimiters[0])), source='<foo-bar>')
519 e = cm.exception
520 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
521 "section 'Foo' already exists")
522 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
523
524 with self.assertRaises(configparser.DuplicateOptionError) as cm:
525 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
526 e = cm.exception
527 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
528 "in section 'Bar' already exists")
529 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000530
531 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000532 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000533 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000534 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000535 " likes it.\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000536 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000537 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000538 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000539 "[Long Line - With Comments!]\n"
540 "test {0[1]} we {comment} can\n"
541 " also {comment} place\n"
542 " comments {comment} in\n"
543 " multiline {comment} values"
Łukasz Langac264c092010-11-20 16:15:37 +0000544 "\n".format(self.delimiters, comment=self.comment_prefixes[0],
545 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000546 )
Fred Drake03c44a32010-02-19 06:08:41 +0000547 if self.allow_no_value:
548 config_string += (
549 "[Valueless]\n"
550 "option-without-value\n"
551 )
552
553 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000554 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000555 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000556 expect_string = (
Łukasz Langac264c092010-11-20 16:15:37 +0000557 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000558 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000559 "\tlong line\n"
560 "\n"
561 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000562 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000563 "\tlikes it.\n"
564 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000565 "[Long Line - With Comments!]\n"
566 "test {equals} we\n"
567 "\talso\n"
568 "\tcomments\n"
569 "\tmultiline\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000570 "\n".format(equals=self.delimiters[0],
571 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000572 )
Fred Drake03c44a32010-02-19 06:08:41 +0000573 if self.allow_no_value:
574 expect_string += (
575 "[Valueless]\n"
576 "option-without-value\n"
577 "\n"
578 )
579 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000580
Fred Drakeabc086f2004-05-18 03:29:52 +0000581 def test_set_string_types(self):
582 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000583 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000584 # Check that we don't get an exception when setting values in
585 # an existing section using strings:
586 class mystr(str):
587 pass
588 cf.set("sect", "option1", "splat")
589 cf.set("sect", "option1", mystr("splat"))
590 cf.set("sect", "option2", "splat")
591 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000592 cf.set("sect", "option1", "splat")
593 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000594
Fred Drake82903142004-05-18 04:24:02 +0000595 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000596 if self.delimiters[0] != '=':
597 # skip reading the file if we're using an incompatible format
598 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000599 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000600 # check when we pass a mix of readable and non-readable files:
601 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000602 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000603 self.assertEqual(parsed_files, [file1])
604 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
605 # check when we pass only a filename:
606 cf = self.newconfig()
607 parsed_files = cf.read(file1)
608 self.assertEqual(parsed_files, [file1])
609 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
610 # check when we pass only missing files:
611 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000612 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000613 self.assertEqual(parsed_files, [])
614 # check when we pass no files:
615 cf = self.newconfig()
616 parsed_files = cf.read([])
617 self.assertEqual(parsed_files, [])
618
Fred Drakec6f28912002-10-25 19:40:49 +0000619 # shared by subclasses
620 def get_interpolation_config(self):
621 return self.fromstring(
622 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000623 "bar{equals}something %(with1)s interpolation (1 step)\n"
624 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
625 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
626 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
627 "with11{equals}%(with10)s\n"
628 "with10{equals}%(with9)s\n"
629 "with9{equals}%(with8)s\n"
630 "with8{equals}%(With7)s\n"
631 "with7{equals}%(WITH6)s\n"
632 "with6{equals}%(with5)s\n"
633 "With5{equals}%(with4)s\n"
634 "WITH4{equals}%(with3)s\n"
635 "with3{equals}%(with2)s\n"
636 "with2{equals}%(with1)s\n"
637 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000638 "\n"
639 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000640 "foo{equals}%(bar)s\n"
641 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000642 "\n"
643 "[Interpolation Error]\n"
Fred Drake54782192002-12-31 06:57:25 +0000644 # no definition for 'reference'
Łukasz Langa5c863392010-11-21 13:41:35 +0000645 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
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"
Łukasz Langa5c863392010-11-21 13:41:35 +0000652 "getdefault{0[1]} |%(default)s|\n".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000653 defaults={"default": "<default>"})
654 L = list(cf.items("section"))
655 L.sort()
656 self.assertEqual(L, expected)
657
Fred Drake8ef67672000-09-27 22:45:25 +0000658
Fred Drakea4923622010-08-09 12:52:45 +0000659class StrictTestCase(BasicTestCase):
660 config_class = configparser.RawConfigParser
661 strict = True
662
663
Georg Brandl96a60ae2010-07-28 13:13:46 +0000664class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000665 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000666
667 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000668 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000669 configparser.ConfigParser: ("something %(with11)s "
670 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000671 configparser.SafeConfigParser: "%(with1)s",
672 }
Fred Drakec6f28912002-10-25 19:40:49 +0000673 cf = self.get_interpolation_config()
674 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000675 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
676 eq(cf.get("Foo", "bar9"),
677 "something with lots of interpolation (9 steps)")
678 eq(cf.get("Foo", "bar10"),
679 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000680 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000681 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000682
Fred Drake54782192002-12-31 06:57:25 +0000683 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000684 rawval = {
685 configparser.ConfigParser: '%(reference)s',
686 configparser.SafeConfigParser: '',
687 }
Fred Drakea4923622010-08-09 12:52:45 +0000688 cf = self.get_interpolation_config()
689 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000690 "Interpolation Error", "name")
691 self.assertEqual(e.reference, "reference")
692 self.assertEqual(e.section, "Interpolation Error")
693 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000694 self.assertEqual(e.args, ('name', 'Interpolation Error',
695 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000696
Fred Drake98e3b292002-10-25 20:42:44 +0000697 def test_items(self):
698 self.check_items_config([('default', '<default>'),
699 ('getdefault', '|<default>|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000700 ('key', '|value|'),
701 ('name', 'value')])
702
David Goodger1cbf2062004-10-03 15:55:09 +0000703 def test_set_nonstring_types(self):
704 cf = self.newconfig()
705 cf.add_section('non-string')
706 cf.set('non-string', 'int', 1)
707 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
708 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
709 '%(list)': '%(list)'})
710 cf.set('non-string', 'string_with_interpolation', '%(list)s')
711 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
712 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
713 self.assertEqual(cf.get('non-string', 'list', raw=True),
714 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
715 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
716 self.assertEqual(cf.get('non-string', 'dict', raw=True),
717 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
718 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
719 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
720 raw=True), '%(list)s')
721 self.assertRaises(ValueError, cf.get, 'non-string',
722 'string_with_interpolation', raw=False)
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000723 cf.add_section(123)
724 cf.set(123, 'this is sick', True)
725 self.assertEqual(cf.get(123, 'this is sick', raw=True), True)
726 with self.assertRaises(TypeError):
727 cf.get(123, 'this is sick')
728 cf.optionxform = lambda x: x
729 cf.set('non-string', 1, 1)
730 self.assertRaises(TypeError, cf.get, 'non-string', 1, 1)
731 self.assertEqual(cf.get('non-string', 1, raw=True), 1)
David Goodger1cbf2062004-10-03 15:55:09 +0000732
Georg Brandl96a60ae2010-07-28 13:13:46 +0000733class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
734 delimiters = (':=', '$')
735 comment_prefixes = ('//', '"')
736
Łukasz Langac264c092010-11-20 16:15:37 +0000737class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
738 default_section = 'general'
739
Georg Brandl96a60ae2010-07-28 13:13:46 +0000740class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000741 config_class = configparser.ConfigParser
742 wonderful_spam = ("I'm having spam spam spam spam "
743 "spam spam spam beaked beans spam "
744 "spam spam and spam!").replace(' ', '\t\n')
745
746 def setUp(self):
747 cf = self.newconfig()
748 for i in range(100):
749 s = 'section{}'.format(i)
750 cf.add_section(s)
751 for j in range(10):
752 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
753 with open(support.TESTFN, 'w') as f:
754 cf.write(f)
755
756 def tearDown(self):
757 os.unlink(support.TESTFN)
758
759 def test_dominating_multiline_values(self):
760 # We're reading from file because this is where the code changed
761 # during performance updates in Python 3.2
762 cf_from_file = self.newconfig()
763 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000764 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000765 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
766 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000767
Georg Brandl96a60ae2010-07-28 13:13:46 +0000768class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000769 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000770
771 def test_interpolation(self):
772 cf = self.get_interpolation_config()
773 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000774 eq(cf.get("Foo", "bar"),
775 "something %(with1)s interpolation (1 step)")
776 eq(cf.get("Foo", "bar9"),
777 "something %(with9)s lots of interpolation (9 steps)")
778 eq(cf.get("Foo", "bar10"),
779 "something %(with10)s lots of interpolation (10 steps)")
780 eq(cf.get("Foo", "bar11"),
781 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000782
Fred Drake98e3b292002-10-25 20:42:44 +0000783 def test_items(self):
784 self.check_items_config([('default', '<default>'),
785 ('getdefault', '|%(default)s|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000786 ('key', '|%(name)s|'),
787 ('name', 'value')])
788
David Goodger1cbf2062004-10-03 15:55:09 +0000789 def test_set_nonstring_types(self):
790 cf = self.newconfig()
791 cf.add_section('non-string')
792 cf.set('non-string', 'int', 1)
793 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
794 cf.set('non-string', 'dict', {'pi': 3.14159})
795 self.assertEqual(cf.get('non-string', 'int'), 1)
796 self.assertEqual(cf.get('non-string', 'list'),
797 [0, 1, 1, 2, 3, 5, 8, 13])
798 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000799 cf.add_section(123)
800 cf.set(123, 'this is sick', True)
801 self.assertEqual(cf.get(123, 'this is sick'), True)
802 if cf._dict.__class__ is configparser._default_dict:
803 # would not work for SortedDict; only checking for the most common
804 # default dictionary (OrderedDict)
805 cf.optionxform = lambda x: x
806 cf.set('non-string', 1, 1)
807 self.assertEqual(cf.get('non-string', 1), 1)
Tim Petersab9b32c2004-10-03 18:35:19 +0000808
Georg Brandl96a60ae2010-07-28 13:13:46 +0000809class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
810 delimiters = (':=', '$')
811 comment_prefixes = ('//', '"')
812
813class RawConfigParserTestSambaConf(BasicTestCase):
814 config_class = configparser.RawConfigParser
815 comment_prefixes = ('#', ';', '//', '----')
816 empty_lines_in_values = False
817
818 def test_reading(self):
819 smbconf = support.findfile("cfgparser.2")
820 # check when we pass a mix of readable and non-readable files:
821 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000822 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000823 self.assertEqual(parsed_files, [smbconf])
824 sections = ['global', 'homes', 'printers',
825 'print$', 'pdf-generator', 'tmp', 'Agustin']
826 self.assertEqual(cf.sections(), sections)
827 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
828 self.assertEqual(cf.getint("global", "max log size"), 50)
829 self.assertEqual(cf.get("global", "hosts allow"), "127.")
830 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000831
Fred Drake0eebd5c2002-10-25 21:52:00 +0000832class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000833 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000834
835 def test_safe_interpolation(self):
836 # See http://www.python.org/sf/511737
837 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000838 "option1{eq}xxx\n"
839 "option2{eq}%(option1)s/xxx\n"
840 "ok{eq}%(option1)s/%%s\n"
841 "not_ok{eq}%(option2)s/%%s".format(
842 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000843 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
844 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
845
Guido van Rossumd8faa362007-04-27 19:54:29 +0000846 def test_set_malformatted_interpolation(self):
847 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000848 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000849
850 self.assertEqual(cf.get('sect', "option1"), "foo")
851
852 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
853 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
854 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
855
856 self.assertEqual(cf.get('sect', "option1"), "foo")
857
Georg Brandl1f9fa312009-04-27 16:42:58 +0000858 # bug #5741: double percents are *not* malformed
859 cf.set("sect", "option2", "foo%%bar")
860 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
861
David Goodger1cbf2062004-10-03 15:55:09 +0000862 def test_set_nonstring_types(self):
863 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000864 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000865 # Check that we get a TypeError when setting non-string values
866 # in an existing section:
867 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
868 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
869 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
870 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
871 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
872 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000873 self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
874 self.assertRaises(TypeError, cf.add_section, 123)
David Goodger1cbf2062004-10-03 15:55:09 +0000875
Łukasz Langac264c092010-11-20 16:15:37 +0000876 def test_add_section_default(self):
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000877 cf = self.newconfig()
Łukasz Langac264c092010-11-20 16:15:37 +0000878 self.assertRaises(ValueError, cf.add_section, self.default_section)
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000879
Łukasz Langab6a6f5f2010-12-03 16:28:00 +0000880class SafeConfigParserTestCaseExtendedInterpolation(BasicTestCase):
881 config_class = configparser.SafeConfigParser
882 interpolation = configparser.ExtendedInterpolation()
883 default_section = 'common'
884
885 def test_extended_interpolation(self):
886 cf = self.fromstring(textwrap.dedent("""
887 [common]
888 favourite Beatle = Paul
889 favourite color = green
890
891 [tom]
892 favourite band = ${favourite color} day
893 favourite pope = John ${favourite Beatle} II
894 sequel = ${favourite pope}I
895
896 [ambv]
897 favourite Beatle = George
898 son of Edward VII = ${favourite Beatle} V
899 son of George V = ${son of Edward VII}I
900
901 [stanley]
902 favourite Beatle = ${ambv:favourite Beatle}
903 favourite pope = ${tom:favourite pope}
904 favourite color = black
905 favourite state of mind = paranoid
906 favourite movie = soylent ${common:favourite color}
907 favourite song = ${favourite color} sabbath - ${favourite state of mind}
908 """).strip())
909
910 eq = self.assertEqual
911 eq(cf['common']['favourite Beatle'], 'Paul')
912 eq(cf['common']['favourite color'], 'green')
913 eq(cf['tom']['favourite Beatle'], 'Paul')
914 eq(cf['tom']['favourite color'], 'green')
915 eq(cf['tom']['favourite band'], 'green day')
916 eq(cf['tom']['favourite pope'], 'John Paul II')
917 eq(cf['tom']['sequel'], 'John Paul III')
918 eq(cf['ambv']['favourite Beatle'], 'George')
919 eq(cf['ambv']['favourite color'], 'green')
920 eq(cf['ambv']['son of Edward VII'], 'George V')
921 eq(cf['ambv']['son of George V'], 'George VI')
922 eq(cf['stanley']['favourite Beatle'], 'George')
923 eq(cf['stanley']['favourite color'], 'black')
924 eq(cf['stanley']['favourite state of mind'], 'paranoid')
925 eq(cf['stanley']['favourite movie'], 'soylent green')
926 eq(cf['stanley']['favourite pope'], 'John Paul II')
927 eq(cf['stanley']['favourite song'],
928 'black sabbath - paranoid')
929
930 def test_endless_loop(self):
931 cf = self.fromstring(textwrap.dedent("""
932 [one for you]
933 ping = ${one for me:pong}
934
935 [one for me]
936 pong = ${one for you:ping}
937 """).strip())
938
939 with self.assertRaises(configparser.InterpolationDepthError):
940 cf['one for you']['ping']
941
942
943
Georg Brandl96a60ae2010-07-28 13:13:46 +0000944class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
945 delimiters = (':=', '$')
946 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000947
948class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
949 allow_no_value = True
950
Georg Brandl8dcaa732010-07-29 12:17:40 +0000951class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
952 config_class = configparser.SafeConfigParser
953 delimiters = {'='}
954 comment_prefixes = {'#'}
955 allow_no_value = True
956
957 def test_cfgparser_dot_3(self):
958 tricky = support.findfile("cfgparser.3")
959 cf = self.newconfig()
960 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
961 self.assertEqual(cf.sections(), ['strange',
962 'corruption',
963 'yeah, sections can be '
964 'indented as well',
965 'another one!',
966 'no values here',
967 'tricky interpolation',
968 'more interpolation'])
Łukasz Langac264c092010-11-20 16:15:37 +0000969 self.assertEqual(cf.getint(self.default_section, 'go',
Fred Drakecc645b92010-09-04 04:35:34 +0000970 vars={'interpolate': '-1'}), -1)
971 with self.assertRaises(ValueError):
972 # no interpolation will happen
Łukasz Langac264c092010-11-20 16:15:37 +0000973 cf.getint(self.default_section, 'go', raw=True,
974 vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000975 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
976 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
977 longname = 'yeah, sections can be indented as well'
978 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000979 self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000980 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
981 # `go` from DEFAULT
982 with self.assertRaises(configparser.InterpolationMissingOptionError):
983 cf.items('no values here')
984 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
985 self.assertEqual(cf.get('tricky interpolation', 'lets'),
986 cf.get('tricky interpolation', 'go'))
987 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
988
989 def test_unicode_failure(self):
990 tricky = support.findfile("cfgparser.3")
991 cf = self.newconfig()
992 with self.assertRaises(UnicodeDecodeError):
993 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000994
Fred Drake88444412010-09-03 04:22:36 +0000995
996class Issue7005TestCase(unittest.TestCase):
997 """Test output when None is set() as a value and allow_no_value == False.
998
999 http://bugs.python.org/issue7005
1000
1001 """
1002
1003 expected_output = "[section]\noption = None\n\n"
1004
1005 def prepare(self, config_class):
1006 # This is the default, but that's the point.
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00001007 with warnings.catch_warnings():
1008 warnings.simplefilter("ignore", category=DeprecationWarning)
1009 cp = config_class(allow_no_value=False)
Fred Drake88444412010-09-03 04:22:36 +00001010 cp.add_section("section")
1011 cp.set("section", "option", None)
1012 sio = io.StringIO()
1013 cp.write(sio)
1014 return sio.getvalue()
1015
1016 def test_none_as_value_stringified(self):
1017 output = self.prepare(configparser.ConfigParser)
1018 self.assertEqual(output, self.expected_output)
1019
1020 def test_none_as_value_stringified_raw(self):
1021 output = self.prepare(configparser.RawConfigParser)
1022 self.assertEqual(output, self.expected_output)
1023
1024
Thomas Wouters89f507f2006-12-13 04:49:30 +00001025class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +00001026 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +00001027
1028 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +00001029 cf = self.fromstring("[b]\n"
1030 "o4=1\n"
1031 "o3=2\n"
1032 "o2=3\n"
1033 "o1=4\n"
1034 "[a]\n"
1035 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +00001036 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +00001037 cf.write(output)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001038 self.assertEqual(output.getvalue(),
1039 "[a]\n"
1040 "k = v\n\n"
1041 "[b]\n"
1042 "o1 = 4\n"
1043 "o2 = 3\n"
1044 "o3 = 2\n"
1045 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +00001046
Fred Drake03c44a32010-02-19 06:08:41 +00001047
Georg Brandl96a60ae2010-07-28 13:13:46 +00001048class CompatibleTestCase(CfgParserTestCaseClass):
1049 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +00001050 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +00001051
1052 def test_comment_handling(self):
1053 config_string = textwrap.dedent("""\
1054 [Commented Bar]
1055 baz=qwe ; a comment
1056 foo: bar # not a comment!
1057 # but this is a comment
1058 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +00001059 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +00001060 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +00001061 """)
1062 cf = self.fromstring(config_string)
1063 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
1064 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +00001065 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +00001066
1067
Fred Drakec6f28912002-10-25 19:40:49 +00001068def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001069 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +00001070 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001071 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001072 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001073 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001074 RawConfigParserTestCaseNonStandardDelimiters,
1075 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +00001076 SafeConfigParserTestCase,
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00001077 SafeConfigParserTestCaseExtendedInterpolation,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001078 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +00001079 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +00001080 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001081 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +00001082 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +00001083 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001084 CompatibleTestCase,
Łukasz Langac264c092010-11-20 16:15:37 +00001085 ConfigParserTestCaseNonStandardDefaultSection,
Fred Drake03c44a32010-02-19 06:08:41 +00001086 )
1087
Łukasz Langa535c0772010-12-04 13:48:13 +00001088def test_coverage(coverdir):
1089 trace = support.import_module('trace')
1090 tracer=trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix,], trace=0,
1091 count=1)
1092 tracer.run('test_main()')
1093 r=tracer.results()
1094 print("Writing coverage results...")
1095 r.write_results(show_missing=True, summary=True, coverdir=coverdir)
Fred Drake3af0eb82002-10-25 18:09:24 +00001096
Fred Drakec6f28912002-10-25 19:40:49 +00001097if __name__ == "__main__":
Łukasz Langa535c0772010-12-04 13:48:13 +00001098 if "-c" in sys.argv:
1099 test_coverage('/tmp/cmd.cover')
1100 else:
1101 test_main()