blob: f7e240f119c519b15a9dfc7020622720753cf41f [file] [log] [blame]
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001import collections
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +00002import configparser
Guido van Rossum34d19282007-08-09 01:03:29 +00003import io
Brian Curtin9a27b0c2010-07-26 00:27:10 +00004import os
Fred Drakec6f28912002-10-25 19:40:49 +00005import unittest
Georg Brandl96a60ae2010-07-28 13:13:46 +00006import textwrap
Fred Drake8ef67672000-09-27 22:45:25 +00007
Benjamin Petersonee8712c2008-05-20 21:35:26 +00008from test import support
Fred Drake3d5f7e82000-12-04 16:30:40 +00009
Raymond Hettingerf80680d2008-02-06 00:07:11 +000010class SortedDict(collections.UserDict):
Fred Drake03c44a32010-02-19 06:08:41 +000011
Thomas Wouters89f507f2006-12-13 04:49:30 +000012 def items(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000013 return sorted(self.data.items())
Thomas Wouters89f507f2006-12-13 04:49:30 +000014
15 def keys(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000016 return sorted(self.data.keys())
Thomas Wouters9fe394c2007-02-05 01:24:16 +000017
Thomas Wouters89f507f2006-12-13 04:49:30 +000018 def values(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000019 return [i[1] for i in self.items()]
Thomas Wouters89f507f2006-12-13 04:49:30 +000020
21 def iteritems(self): return iter(self.items())
22 def iterkeys(self): return iter(self.keys())
23 __iter__ = iterkeys
24 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000025
Fred Drake03c44a32010-02-19 06:08:41 +000026
Georg Brandl96a60ae2010-07-28 13:13:46 +000027class CfgParserTestCaseClass(unittest.TestCase):
Fred Drake03c44a32010-02-19 06:08:41 +000028 allow_no_value = False
Georg Brandl96a60ae2010-07-28 13:13:46 +000029 delimiters = ('=', ':')
30 comment_prefixes = (';', '#')
31 empty_lines_in_values = True
32 dict_type = configparser._default_dict
Fred Drakea4923622010-08-09 12:52:45 +000033 strict = False
Fred Drake03c44a32010-02-19 06:08:41 +000034
Fred Drakec6f28912002-10-25 19:40:49 +000035 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000036 arguments = dict(
Fred Drakea4923622010-08-09 12:52:45 +000037 defaults=defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000038 allow_no_value=self.allow_no_value,
39 delimiters=self.delimiters,
40 comment_prefixes=self.comment_prefixes,
41 empty_lines_in_values=self.empty_lines_in_values,
42 dict_type=self.dict_type,
Fred Drakea4923622010-08-09 12:52:45 +000043 strict=self.strict,
Georg Brandl96a60ae2010-07-28 13:13:46 +000044 )
Fred Drakea4923622010-08-09 12:52:45 +000045 return self.config_class(**arguments)
Fred Drake8ef67672000-09-27 22:45:25 +000046
Fred Drakec6f28912002-10-25 19:40:49 +000047 def fromstring(self, string, defaults=None):
48 cf = self.newconfig(defaults)
Fred Drakea4923622010-08-09 12:52:45 +000049 cf.read_string(string)
Fred Drakec6f28912002-10-25 19:40:49 +000050 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000051
Georg Brandl96a60ae2010-07-28 13:13:46 +000052class BasicTestCase(CfgParserTestCaseClass):
53
Fred Drakea4923622010-08-09 12:52:45 +000054 def basic_test(self, cf):
Fred Drakec6f28912002-10-25 19:40:49 +000055 L = cf.sections()
56 L.sort()
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 ]
67 if self.allow_no_value:
Fred Drakecc645b92010-09-04 04:35:34 +000068 E.append('NoValue')
Fred Drake03c44a32010-02-19 06:08:41 +000069 E.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000070 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000071 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000072
Fred Drakec6f28912002-10-25 19:40:49 +000073 # The use of spaces in the section names serves as a
74 # regression test for SourceForge bug #583248:
75 # http://www.python.org/sf/583248
76 eq(cf.get('Foo Bar', 'foo'), 'bar')
77 eq(cf.get('Spacey Bar', 'foo'), 'bar')
Georg Brandl96a60ae2010-07-28 13:13:46 +000078 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar')
79 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +000080 eq(cf.get('Commented Bar', 'foo'), 'bar')
Georg Brandl96a60ae2010-07-28 13:13:46 +000081 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +000082 eq(cf.get('Spaces', 'key with spaces'), 'value')
83 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc645b92010-09-04 04:35:34 +000084 eq(cf.getint('Types', 'int'), 42)
85 eq(cf.get('Types', 'int'), "42")
86 self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
87 eq(cf.get('Types', 'float'), "0.44")
88 eq(cf.getboolean('Types', 'boolean'), False)
Fred Drake03c44a32010-02-19 06:08:41 +000089 if self.allow_no_value:
90 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +000091
Fred Drakecc645b92010-09-04 04:35:34 +000092 # test vars= and default=
93 eq(cf.get('Foo Bar', 'foo', default='baz'), 'bar')
94 eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
95 with self.assertRaises(configparser.NoSectionError):
96 cf.get('No Such Foo Bar', 'foo')
97 with self.assertRaises(configparser.NoOptionError):
98 cf.get('Foo Bar', 'no-such-foo')
99 eq(cf.get('No Such Foo Bar', 'foo', default='baz'), 'baz')
100 eq(cf.get('Foo Bar', 'no-such-foo', default='baz'), 'baz')
101 eq(cf.get('Spacey Bar', 'foo', default=None), 'bar')
102 eq(cf.get('No Such Spacey Bar', 'foo', default=None), None)
103 eq(cf.getint('Types', 'int', default=18), 42)
104 eq(cf.getint('Types', 'no-such-int', default=18), 18)
105 eq(cf.getint('Types', 'no-such-int', default="18"), "18") # sic!
106 self.assertAlmostEqual(cf.getfloat('Types', 'float',
107 default=0.0), 0.44)
108 self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
109 default=0.0), 0.0)
110 eq(cf.getfloat('Types', 'no-such-float', default="0.0"), "0.0") # sic!
111 eq(cf.getboolean('Types', 'boolean', default=True), False)
112 eq(cf.getboolean('Types', 'no-such-boolean', default="yes"),
113 "yes") # sic!
114 eq(cf.getboolean('Types', 'no-such-boolean', default=True), True)
115 eq(cf.getboolean('No Such Types', 'boolean', default=True), True)
116 if self.allow_no_value:
117 eq(cf.get('NoValue', 'option-without-value', default=False), None)
118 eq(cf.get('NoValue', 'no-such-option-without-value',
119 default=False), False)
120
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000121 self.assertNotIn('__name__', cf.options("Foo Bar"),
122 '__name__ "option" should not be exposed by the API!')
Fred Drakec6f28912002-10-25 19:40:49 +0000123
124 # Make sure the right things happen for remove_option();
125 # added to include check for SourceForge bug #123324:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000126 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000127 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000128 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000129 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000130 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000131 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000132 " that was removed")
133
Michael Foordbd6c0792010-07-25 23:09:25 +0000134 with self.assertRaises(configparser.NoSectionError) as cm:
135 cf.remove_option('No Such Section', 'foo')
136 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000137
138 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000139 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000140
Fred Drakea4923622010-08-09 12:52:45 +0000141 def test_basic(self):
142 config_string = """\
143[Foo Bar]
144foo{0[0]}bar
145[Spacey Bar]
146foo {0[0]} bar
147[Spacey Bar From The Beginning]
148 foo {0[0]} bar
149 baz {0[0]} qwe
150[Commented Bar]
151foo{0[1]} bar {1[1]} comment
152baz{0[0]}qwe {1[0]}another one
153[Long Line]
154foo{0[1]} this line is much, much longer than my editor
155 likes it.
156[Section\\with$weird%characters[\t]
157[Internationalized Stuff]
158foo[bg]{0[1]} Bulgarian
159foo{0[0]}Default
160foo[en]{0[0]}English
161foo[de]{0[0]}Deutsch
162[Spaces]
163key with spaces {0[1]} value
164another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000165[Types]
166int {0[1]} 42
167float {0[0]} 0.44
168boolean {0[0]} NO
Fred Drakea4923622010-08-09 12:52:45 +0000169""".format(self.delimiters, self.comment_prefixes)
170 if self.allow_no_value:
171 config_string += (
172 "[NoValue]\n"
173 "option-without-value\n"
174 )
175 cf = self.fromstring(config_string)
176 self.basic_test(cf)
177 if self.strict:
178 with self.assertRaises(configparser.DuplicateOptionError):
179 cf.read_string(textwrap.dedent("""\
180 [Duplicate Options Here]
181 option {0[0]} with a value
182 option {0[1]} with another value
183 """.format(self.delimiters)))
184 with self.assertRaises(configparser.DuplicateSectionError):
185 cf.read_string(textwrap.dedent("""\
186 [And Now For Something]
187 completely different {0[0]} True
188 [And Now For Something]
189 the larch {0[1]} 1
190 """.format(self.delimiters)))
191 else:
192 cf.read_string(textwrap.dedent("""\
193 [Duplicate Options Here]
194 option {0[0]} with a value
195 option {0[1]} with another value
196 """.format(self.delimiters)))
197
198 cf.read_string(textwrap.dedent("""\
199 [And Now For Something]
200 completely different {0[0]} True
201 [And Now For Something]
202 the larch {0[1]} 1
203 """.format(self.delimiters)))
204
205 def test_basic_from_dict(self):
206 config = {
207 "Foo Bar": {
208 "foo": "bar",
209 },
210 "Spacey Bar": {
211 "foo": "bar",
212 },
213 "Spacey Bar From The Beginning": {
214 "foo": "bar",
215 "baz": "qwe",
216 },
217 "Commented Bar": {
218 "foo": "bar",
219 "baz": "qwe",
220 },
221 "Long Line": {
222 "foo": "this line is much, much longer than my editor\nlikes "
223 "it.",
224 },
225 "Section\\with$weird%characters[\t": {
226 },
227 "Internationalized Stuff": {
228 "foo[bg]": "Bulgarian",
229 "foo": "Default",
230 "foo[en]": "English",
231 "foo[de]": "Deutsch",
232 },
233 "Spaces": {
234 "key with spaces": "value",
235 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000236 },
237 "Types": {
238 "int": 42,
239 "float": 0.44,
240 "boolean": False,
241 },
Fred Drakea4923622010-08-09 12:52:45 +0000242 }
243 if self.allow_no_value:
244 config.update({
245 "NoValue": {
246 "option-without-value": None,
247 }
248 })
249 cf = self.newconfig()
250 cf.read_dict(config)
251 self.basic_test(cf)
252 if self.strict:
253 with self.assertRaises(configparser.DuplicateOptionError):
254 cf.read_dict({
255 "Duplicate Options Here": {
256 'option': 'with a value',
257 'OPTION': 'with another value',
258 },
259 })
260 else:
261 cf.read_dict({
262 "Duplicate Options Here": {
263 'option': 'with a value',
264 'OPTION': 'with another value',
265 },
266 })
267
268
Fred Drakec6f28912002-10-25 19:40:49 +0000269 def test_case_sensitivity(self):
270 cf = self.newconfig()
271 cf.add_section("A")
272 cf.add_section("a")
273 L = cf.sections()
274 L.sort()
275 eq = self.assertEqual
276 eq(L, ["A", "a"])
277 cf.set("a", "B", "value")
278 eq(cf.options("a"), ["b"])
279 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000280 "could not locate option, expecting case-insensitive option names")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000281 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000282 cf.set("A", "A-B", "A-B value")
283 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000284 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000285 cf.has_option("A", opt),
286 "has_option() returned false for option which should exist")
287 eq(cf.options("A"), ["a-b"])
288 eq(cf.options("a"), ["b"])
289 cf.remove_option("a", "B")
290 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000291
Fred Drakec6f28912002-10-25 19:40:49 +0000292 # SF bug #432369:
293 cf = self.fromstring(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000294 "[MySection]\nOption{} first line\n\tsecond line\n".format(
295 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000296 eq(cf.options("MySection"), ["option"])
297 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000298
Fred Drakec6f28912002-10-25 19:40:49 +0000299 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000300 cf = self.fromstring("[section]\n"
301 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000302 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000303 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000304
Fred Drake3c823aa2001-02-26 21:55:34 +0000305
David Goodger68a1abd2004-10-03 15:40:25 +0000306 def test_default_case_sensitivity(self):
307 cf = self.newconfig({"foo": "Bar"})
308 self.assertEqual(
309 cf.get("DEFAULT", "Foo"), "Bar",
310 "could not locate option, expecting case-insensitive option names")
311 cf = self.newconfig({"Foo": "Bar"})
312 self.assertEqual(
313 cf.get("DEFAULT", "Foo"), "Bar",
314 "could not locate option, expecting case-insensitive defaults")
315
Fred Drakec6f28912002-10-25 19:40:49 +0000316 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000317 cf = self.newconfig()
318 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000319 "[Foo]\n"
320 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000321 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000322 "[Foo]\n"
323 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000324 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000325 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000326 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000327 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000328 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000329 "[Foo]\n wrong-indent\n")
330 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000331 # read_file on a real file
332 tricky = support.findfile("cfgparser.3")
333 if self.delimiters[0] == '=':
334 error = configparser.ParsingError
335 expected = (tricky,)
336 else:
337 error = configparser.MissingSectionHeaderError
338 expected = (tricky, 1,
339 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000340 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000341 e = self.parse_error(cf, error, f)
342 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000343
Fred Drakea4923622010-08-09 12:52:45 +0000344 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000345 if hasattr(src, 'readline'):
346 sio = src
347 else:
348 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000349 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000350 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000351 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000352
Fred Drakec6f28912002-10-25 19:40:49 +0000353 def test_query_errors(self):
354 cf = self.newconfig()
355 self.assertEqual(cf.sections(), [],
356 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000357 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000358 "new ConfigParser should have no acknowledged "
359 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000360 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000361 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000362 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000363 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000364 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000365 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000366 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000367 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000368 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000369
Fred Drakea4923622010-08-09 12:52:45 +0000370 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000371 try:
Fred Drakea4923622010-08-09 12:52:45 +0000372 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000373 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000374 return e
375 else:
376 self.fail("expected exception type %s.%s"
377 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000378
Fred Drakec6f28912002-10-25 19:40:49 +0000379 def test_boolean(self):
380 cf = self.fromstring(
381 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000382 "T1{equals}1\n"
383 "T2{equals}TRUE\n"
384 "T3{equals}True\n"
385 "T4{equals}oN\n"
386 "T5{equals}yes\n"
387 "F1{equals}0\n"
388 "F2{equals}FALSE\n"
389 "F3{equals}False\n"
390 "F4{equals}oFF\n"
391 "F5{equals}nO\n"
392 "E1{equals}2\n"
393 "E2{equals}foo\n"
394 "E3{equals}-1\n"
395 "E4{equals}0.1\n"
396 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000397 )
398 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000399 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
400 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000401 self.assertRaises(ValueError,
402 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000403
Fred Drakec6f28912002-10-25 19:40:49 +0000404 def test_weird_errors(self):
405 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000406 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000407 with self.assertRaises(configparser.DuplicateSectionError) as cm:
408 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000409 e = cm.exception
410 self.assertEqual(str(e), "Section 'Foo' already exists")
411 self.assertEqual(e.args, ("Foo", None, None))
412
413 if self.strict:
414 with self.assertRaises(configparser.DuplicateSectionError) as cm:
415 cf.read_string(textwrap.dedent("""\
416 [Foo]
417 will this be added{equals}True
418 [Bar]
419 what about this{equals}True
420 [Foo]
421 oops{equals}this won't
422 """.format(equals=self.delimiters[0])), source='<foo-bar>')
423 e = cm.exception
424 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
425 "section 'Foo' already exists")
426 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
427
428 with self.assertRaises(configparser.DuplicateOptionError) as cm:
429 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
430 e = cm.exception
431 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
432 "in section 'Bar' already exists")
433 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000434
435 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000436 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000437 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000438 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000439 " likes it.\n"
440 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000441 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000442 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000443 "[Long Line - With Comments!]\n"
444 "test {0[1]} we {comment} can\n"
445 " also {comment} place\n"
446 " comments {comment} in\n"
447 " multiline {comment} values"
448 "\n".format(self.delimiters, comment=self.comment_prefixes[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000449 )
Fred Drake03c44a32010-02-19 06:08:41 +0000450 if self.allow_no_value:
451 config_string += (
452 "[Valueless]\n"
453 "option-without-value\n"
454 )
455
456 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000457 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000458 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000459 expect_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000460 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000461 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000462 "\tlong line\n"
463 "\n"
464 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000465 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000466 "\tlikes it.\n"
467 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000468 "[Long Line - With Comments!]\n"
469 "test {equals} we\n"
470 "\talso\n"
471 "\tcomments\n"
472 "\tmultiline\n"
473 "\n".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000474 )
Fred Drake03c44a32010-02-19 06:08:41 +0000475 if self.allow_no_value:
476 expect_string += (
477 "[Valueless]\n"
478 "option-without-value\n"
479 "\n"
480 )
481 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000482
Fred Drakeabc086f2004-05-18 03:29:52 +0000483 def test_set_string_types(self):
484 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000485 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000486 # Check that we don't get an exception when setting values in
487 # an existing section using strings:
488 class mystr(str):
489 pass
490 cf.set("sect", "option1", "splat")
491 cf.set("sect", "option1", mystr("splat"))
492 cf.set("sect", "option2", "splat")
493 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000494 cf.set("sect", "option1", "splat")
495 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000496
Fred Drake82903142004-05-18 04:24:02 +0000497 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000498 if self.delimiters[0] != '=':
499 # skip reading the file if we're using an incompatible format
500 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000501 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000502 # check when we pass a mix of readable and non-readable files:
503 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000504 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000505 self.assertEqual(parsed_files, [file1])
506 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
507 # check when we pass only a filename:
508 cf = self.newconfig()
509 parsed_files = cf.read(file1)
510 self.assertEqual(parsed_files, [file1])
511 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
512 # check when we pass only missing files:
513 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000514 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000515 self.assertEqual(parsed_files, [])
516 # check when we pass no files:
517 cf = self.newconfig()
518 parsed_files = cf.read([])
519 self.assertEqual(parsed_files, [])
520
Fred Drakec6f28912002-10-25 19:40:49 +0000521 # shared by subclasses
522 def get_interpolation_config(self):
523 return self.fromstring(
524 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000525 "bar{equals}something %(with1)s interpolation (1 step)\n"
526 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
527 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
528 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
529 "with11{equals}%(with10)s\n"
530 "with10{equals}%(with9)s\n"
531 "with9{equals}%(with8)s\n"
532 "with8{equals}%(With7)s\n"
533 "with7{equals}%(WITH6)s\n"
534 "with6{equals}%(with5)s\n"
535 "With5{equals}%(with4)s\n"
536 "WITH4{equals}%(with3)s\n"
537 "with3{equals}%(with2)s\n"
538 "with2{equals}%(with1)s\n"
539 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000540 "\n"
541 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000542 "foo{equals}%(bar)s\n"
543 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000544 "\n"
545 "[Interpolation Error]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000546 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]),
Fred Drake54782192002-12-31 06:57:25 +0000547 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000548 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000549
Fred Drake98e3b292002-10-25 20:42:44 +0000550 def check_items_config(self, expected):
551 cf = self.fromstring(
552 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000553 "name {0[0]} value\n"
554 "key{0[1]} |%(name)s| \n"
555 "getdefault{0[1]} |%(default)s|\n"
556 "getname{0[1]} |%(__name__)s|".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000557 defaults={"default": "<default>"})
558 L = list(cf.items("section"))
559 L.sort()
560 self.assertEqual(L, expected)
561
Fred Drake8ef67672000-09-27 22:45:25 +0000562
Fred Drakea4923622010-08-09 12:52:45 +0000563class StrictTestCase(BasicTestCase):
564 config_class = configparser.RawConfigParser
565 strict = True
566
567
Georg Brandl96a60ae2010-07-28 13:13:46 +0000568class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000569 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000570
571 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000572 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000573 configparser.ConfigParser: ("something %(with11)s "
574 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000575 configparser.SafeConfigParser: "%(with1)s",
576 }
Fred Drakec6f28912002-10-25 19:40:49 +0000577 cf = self.get_interpolation_config()
578 eq = self.assertEqual
579 eq(cf.get("Foo", "getname"), "Foo")
580 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
581 eq(cf.get("Foo", "bar9"),
582 "something with lots of interpolation (9 steps)")
583 eq(cf.get("Foo", "bar10"),
584 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000585 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000586 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000587
Fred Drake54782192002-12-31 06:57:25 +0000588 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000589 rawval = {
590 configparser.ConfigParser: '%(reference)s',
591 configparser.SafeConfigParser: '',
592 }
Fred Drakea4923622010-08-09 12:52:45 +0000593 cf = self.get_interpolation_config()
594 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000595 "Interpolation Error", "name")
596 self.assertEqual(e.reference, "reference")
597 self.assertEqual(e.section, "Interpolation Error")
598 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000599 self.assertEqual(e.args, ('name', 'Interpolation Error',
600 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000601
Fred Drake98e3b292002-10-25 20:42:44 +0000602 def test_items(self):
603 self.check_items_config([('default', '<default>'),
604 ('getdefault', '|<default>|'),
605 ('getname', '|section|'),
606 ('key', '|value|'),
607 ('name', 'value')])
608
David Goodger1cbf2062004-10-03 15:55:09 +0000609 def test_set_nonstring_types(self):
610 cf = self.newconfig()
611 cf.add_section('non-string')
612 cf.set('non-string', 'int', 1)
613 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
614 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
615 '%(list)': '%(list)'})
616 cf.set('non-string', 'string_with_interpolation', '%(list)s')
617 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
618 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
619 self.assertEqual(cf.get('non-string', 'list', raw=True),
620 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
621 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
622 self.assertEqual(cf.get('non-string', 'dict', raw=True),
623 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
624 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
625 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
626 raw=True), '%(list)s')
627 self.assertRaises(ValueError, cf.get, 'non-string',
628 'string_with_interpolation', raw=False)
629
Georg Brandl96a60ae2010-07-28 13:13:46 +0000630class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
631 delimiters = (':=', '$')
632 comment_prefixes = ('//', '"')
633
634class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000635 config_class = configparser.ConfigParser
636 wonderful_spam = ("I'm having spam spam spam spam "
637 "spam spam spam beaked beans spam "
638 "spam spam and spam!").replace(' ', '\t\n')
639
640 def setUp(self):
641 cf = self.newconfig()
642 for i in range(100):
643 s = 'section{}'.format(i)
644 cf.add_section(s)
645 for j in range(10):
646 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
647 with open(support.TESTFN, 'w') as f:
648 cf.write(f)
649
650 def tearDown(self):
651 os.unlink(support.TESTFN)
652
653 def test_dominating_multiline_values(self):
654 # We're reading from file because this is where the code changed
655 # during performance updates in Python 3.2
656 cf_from_file = self.newconfig()
657 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000658 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000659 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
660 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000661
Georg Brandl96a60ae2010-07-28 13:13:46 +0000662class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000663 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000664
665 def test_interpolation(self):
666 cf = self.get_interpolation_config()
667 eq = self.assertEqual
668 eq(cf.get("Foo", "getname"), "%(__name__)s")
669 eq(cf.get("Foo", "bar"),
670 "something %(with1)s interpolation (1 step)")
671 eq(cf.get("Foo", "bar9"),
672 "something %(with9)s lots of interpolation (9 steps)")
673 eq(cf.get("Foo", "bar10"),
674 "something %(with10)s lots of interpolation (10 steps)")
675 eq(cf.get("Foo", "bar11"),
676 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000677
Fred Drake98e3b292002-10-25 20:42:44 +0000678 def test_items(self):
679 self.check_items_config([('default', '<default>'),
680 ('getdefault', '|%(default)s|'),
681 ('getname', '|%(__name__)s|'),
682 ('key', '|%(name)s|'),
683 ('name', 'value')])
684
David Goodger1cbf2062004-10-03 15:55:09 +0000685 def test_set_nonstring_types(self):
686 cf = self.newconfig()
687 cf.add_section('non-string')
688 cf.set('non-string', 'int', 1)
689 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
690 cf.set('non-string', 'dict', {'pi': 3.14159})
691 self.assertEqual(cf.get('non-string', 'int'), 1)
692 self.assertEqual(cf.get('non-string', 'list'),
693 [0, 1, 1, 2, 3, 5, 8, 13])
694 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000695
Georg Brandl96a60ae2010-07-28 13:13:46 +0000696class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
697 delimiters = (':=', '$')
698 comment_prefixes = ('//', '"')
699
700class RawConfigParserTestSambaConf(BasicTestCase):
701 config_class = configparser.RawConfigParser
702 comment_prefixes = ('#', ';', '//', '----')
703 empty_lines_in_values = False
704
705 def test_reading(self):
706 smbconf = support.findfile("cfgparser.2")
707 # check when we pass a mix of readable and non-readable files:
708 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000709 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000710 self.assertEqual(parsed_files, [smbconf])
711 sections = ['global', 'homes', 'printers',
712 'print$', 'pdf-generator', 'tmp', 'Agustin']
713 self.assertEqual(cf.sections(), sections)
714 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
715 self.assertEqual(cf.getint("global", "max log size"), 50)
716 self.assertEqual(cf.get("global", "hosts allow"), "127.")
717 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000718
Fred Drake0eebd5c2002-10-25 21:52:00 +0000719class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000720 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000721
722 def test_safe_interpolation(self):
723 # See http://www.python.org/sf/511737
724 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000725 "option1{eq}xxx\n"
726 "option2{eq}%(option1)s/xxx\n"
727 "ok{eq}%(option1)s/%%s\n"
728 "not_ok{eq}%(option2)s/%%s".format(
729 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000730 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
731 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
732
Guido van Rossumd8faa362007-04-27 19:54:29 +0000733 def test_set_malformatted_interpolation(self):
734 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000735 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000736
737 self.assertEqual(cf.get('sect', "option1"), "foo")
738
739 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
740 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
741 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
742
743 self.assertEqual(cf.get('sect', "option1"), "foo")
744
Georg Brandl1f9fa312009-04-27 16:42:58 +0000745 # bug #5741: double percents are *not* malformed
746 cf.set("sect", "option2", "foo%%bar")
747 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
748
David Goodger1cbf2062004-10-03 15:55:09 +0000749 def test_set_nonstring_types(self):
750 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000751 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000752 # Check that we get a TypeError when setting non-string values
753 # in an existing section:
754 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
755 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
756 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
757 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
758 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
759 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
760
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000761 def test_add_section_default_1(self):
762 cf = self.newconfig()
763 self.assertRaises(ValueError, cf.add_section, "default")
764
765 def test_add_section_default_2(self):
766 cf = self.newconfig()
767 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
768
Georg Brandl96a60ae2010-07-28 13:13:46 +0000769class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
770 delimiters = (':=', '$')
771 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000772
773class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
774 allow_no_value = True
775
Georg Brandl8dcaa732010-07-29 12:17:40 +0000776class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
777 config_class = configparser.SafeConfigParser
778 delimiters = {'='}
779 comment_prefixes = {'#'}
780 allow_no_value = True
781
782 def test_cfgparser_dot_3(self):
783 tricky = support.findfile("cfgparser.3")
784 cf = self.newconfig()
785 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
786 self.assertEqual(cf.sections(), ['strange',
787 'corruption',
788 'yeah, sections can be '
789 'indented as well',
790 'another one!',
791 'no values here',
792 'tricky interpolation',
793 'more interpolation'])
Fred Drakecc645b92010-09-04 04:35:34 +0000794 self.assertEqual(cf.getint('DEFAULT', 'go',
795 vars={'interpolate': '-1'}), -1)
796 with self.assertRaises(ValueError):
797 # no interpolation will happen
798 cf.getint('DEFAULT', 'go', raw=True, vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000799 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
800 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
801 longname = 'yeah, sections can be indented as well'
802 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
803 self.assertEquals(cf.get(longname, 'lets use some Unicode'),
804 '片仮名')
805 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
806 # `go` from DEFAULT
807 with self.assertRaises(configparser.InterpolationMissingOptionError):
808 cf.items('no values here')
809 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
810 self.assertEqual(cf.get('tricky interpolation', 'lets'),
811 cf.get('tricky interpolation', 'go'))
812 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
813
814 def test_unicode_failure(self):
815 tricky = support.findfile("cfgparser.3")
816 cf = self.newconfig()
817 with self.assertRaises(UnicodeDecodeError):
818 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000819
Fred Drake88444412010-09-03 04:22:36 +0000820
821class Issue7005TestCase(unittest.TestCase):
822 """Test output when None is set() as a value and allow_no_value == False.
823
824 http://bugs.python.org/issue7005
825
826 """
827
828 expected_output = "[section]\noption = None\n\n"
829
830 def prepare(self, config_class):
831 # This is the default, but that's the point.
832 cp = config_class(allow_no_value=False)
833 cp.add_section("section")
834 cp.set("section", "option", None)
835 sio = io.StringIO()
836 cp.write(sio)
837 return sio.getvalue()
838
839 def test_none_as_value_stringified(self):
840 output = self.prepare(configparser.ConfigParser)
841 self.assertEqual(output, self.expected_output)
842
843 def test_none_as_value_stringified_raw(self):
844 output = self.prepare(configparser.RawConfigParser)
845 self.assertEqual(output, self.expected_output)
846
847
Thomas Wouters89f507f2006-12-13 04:49:30 +0000848class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000849 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000850
851 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +0000852 cf = self.fromstring("[b]\n"
853 "o4=1\n"
854 "o3=2\n"
855 "o2=3\n"
856 "o1=4\n"
857 "[a]\n"
858 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000859 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +0000860 cf.write(output)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000861 self.assertEquals(output.getvalue(),
862 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000863 "k = v\n\n"
Thomas Wouters89f507f2006-12-13 04:49:30 +0000864 "[b]\n"
865 "o1 = 4\n"
866 "o2 = 3\n"
867 "o3 = 2\n"
868 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000869
Fred Drake03c44a32010-02-19 06:08:41 +0000870
Georg Brandl96a60ae2010-07-28 13:13:46 +0000871class CompatibleTestCase(CfgParserTestCaseClass):
872 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +0000873 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +0000874
875 def test_comment_handling(self):
876 config_string = textwrap.dedent("""\
877 [Commented Bar]
878 baz=qwe ; a comment
879 foo: bar # not a comment!
880 # but this is a comment
881 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000882 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +0000883 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +0000884 """)
885 cf = self.fromstring(config_string)
886 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
887 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000888 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000889
890
Fred Drakec6f28912002-10-25 19:40:49 +0000891def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000892 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000893 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000894 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000895 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000896 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000897 RawConfigParserTestCaseNonStandardDelimiters,
898 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000899 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000900 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000901 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000902 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000903 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +0000904 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +0000905 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000906 CompatibleTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +0000907 )
908
Fred Drake3af0eb82002-10-25 18:09:24 +0000909
Fred Drakec6f28912002-10-25 19:40:49 +0000910if __name__ == "__main__":
911 test_main()