blob: 3079cfb80ce6bbdd74b2a5d46752d4b84ae72106 [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, ('<???>',))
Fred Drake168bead2001-10-08 17:13:12 +0000331
Fred Drakea4923622010-08-09 12:52:45 +0000332 def parse_error(self, cf, exc, src):
Guido van Rossum34d19282007-08-09 01:03:29 +0000333 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000334 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000335 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000336 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000337
Fred Drakec6f28912002-10-25 19:40:49 +0000338 def test_query_errors(self):
339 cf = self.newconfig()
340 self.assertEqual(cf.sections(), [],
341 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000342 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000343 "new ConfigParser should have no acknowledged "
344 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000345 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000346 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000347 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000348 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000349 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000350 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000351 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000352 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000353 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000354
Fred Drakea4923622010-08-09 12:52:45 +0000355 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000356 try:
Fred Drakea4923622010-08-09 12:52:45 +0000357 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000358 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000359 return e
360 else:
361 self.fail("expected exception type %s.%s"
362 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000363
Fred Drakec6f28912002-10-25 19:40:49 +0000364 def test_boolean(self):
365 cf = self.fromstring(
366 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000367 "T1{equals}1\n"
368 "T2{equals}TRUE\n"
369 "T3{equals}True\n"
370 "T4{equals}oN\n"
371 "T5{equals}yes\n"
372 "F1{equals}0\n"
373 "F2{equals}FALSE\n"
374 "F3{equals}False\n"
375 "F4{equals}oFF\n"
376 "F5{equals}nO\n"
377 "E1{equals}2\n"
378 "E2{equals}foo\n"
379 "E3{equals}-1\n"
380 "E4{equals}0.1\n"
381 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000382 )
383 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000384 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
385 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000386 self.assertRaises(ValueError,
387 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000388
Fred Drakec6f28912002-10-25 19:40:49 +0000389 def test_weird_errors(self):
390 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000391 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000392 with self.assertRaises(configparser.DuplicateSectionError) as cm:
393 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000394 e = cm.exception
395 self.assertEqual(str(e), "Section 'Foo' already exists")
396 self.assertEqual(e.args, ("Foo", None, None))
397
398 if self.strict:
399 with self.assertRaises(configparser.DuplicateSectionError) as cm:
400 cf.read_string(textwrap.dedent("""\
401 [Foo]
402 will this be added{equals}True
403 [Bar]
404 what about this{equals}True
405 [Foo]
406 oops{equals}this won't
407 """.format(equals=self.delimiters[0])), source='<foo-bar>')
408 e = cm.exception
409 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
410 "section 'Foo' already exists")
411 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
412
413 with self.assertRaises(configparser.DuplicateOptionError) as cm:
414 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
415 e = cm.exception
416 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
417 "in section 'Bar' already exists")
418 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000419
420 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000421 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000422 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000423 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000424 " likes it.\n"
425 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000426 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000427 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000428 "[Long Line - With Comments!]\n"
429 "test {0[1]} we {comment} can\n"
430 " also {comment} place\n"
431 " comments {comment} in\n"
432 " multiline {comment} values"
433 "\n".format(self.delimiters, comment=self.comment_prefixes[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000434 )
Fred Drake03c44a32010-02-19 06:08:41 +0000435 if self.allow_no_value:
436 config_string += (
437 "[Valueless]\n"
438 "option-without-value\n"
439 )
440
441 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000442 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000443 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000444 expect_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000445 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000446 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000447 "\tlong line\n"
448 "\n"
449 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000450 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000451 "\tlikes it.\n"
452 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000453 "[Long Line - With Comments!]\n"
454 "test {equals} we\n"
455 "\talso\n"
456 "\tcomments\n"
457 "\tmultiline\n"
458 "\n".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000459 )
Fred Drake03c44a32010-02-19 06:08:41 +0000460 if self.allow_no_value:
461 expect_string += (
462 "[Valueless]\n"
463 "option-without-value\n"
464 "\n"
465 )
466 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000467
Fred Drakeabc086f2004-05-18 03:29:52 +0000468 def test_set_string_types(self):
469 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000470 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000471 # Check that we don't get an exception when setting values in
472 # an existing section using strings:
473 class mystr(str):
474 pass
475 cf.set("sect", "option1", "splat")
476 cf.set("sect", "option1", mystr("splat"))
477 cf.set("sect", "option2", "splat")
478 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000479 cf.set("sect", "option1", "splat")
480 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000481
Fred Drake82903142004-05-18 04:24:02 +0000482 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000483 if self.delimiters[0] != '=':
484 # skip reading the file if we're using an incompatible format
485 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000486 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000487 # check when we pass a mix of readable and non-readable files:
488 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000489 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000490 self.assertEqual(parsed_files, [file1])
491 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
492 # check when we pass only a filename:
493 cf = self.newconfig()
494 parsed_files = cf.read(file1)
495 self.assertEqual(parsed_files, [file1])
496 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
497 # check when we pass only missing files:
498 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000499 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000500 self.assertEqual(parsed_files, [])
501 # check when we pass no files:
502 cf = self.newconfig()
503 parsed_files = cf.read([])
504 self.assertEqual(parsed_files, [])
505
Fred Drakec6f28912002-10-25 19:40:49 +0000506 # shared by subclasses
507 def get_interpolation_config(self):
508 return self.fromstring(
509 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000510 "bar{equals}something %(with1)s interpolation (1 step)\n"
511 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
512 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
513 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
514 "with11{equals}%(with10)s\n"
515 "with10{equals}%(with9)s\n"
516 "with9{equals}%(with8)s\n"
517 "with8{equals}%(With7)s\n"
518 "with7{equals}%(WITH6)s\n"
519 "with6{equals}%(with5)s\n"
520 "With5{equals}%(with4)s\n"
521 "WITH4{equals}%(with3)s\n"
522 "with3{equals}%(with2)s\n"
523 "with2{equals}%(with1)s\n"
524 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000525 "\n"
526 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000527 "foo{equals}%(bar)s\n"
528 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000529 "\n"
530 "[Interpolation Error]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000531 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]),
Fred Drake54782192002-12-31 06:57:25 +0000532 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000533 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000534
Fred Drake98e3b292002-10-25 20:42:44 +0000535 def check_items_config(self, expected):
536 cf = self.fromstring(
537 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000538 "name {0[0]} value\n"
539 "key{0[1]} |%(name)s| \n"
540 "getdefault{0[1]} |%(default)s|\n"
541 "getname{0[1]} |%(__name__)s|".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000542 defaults={"default": "<default>"})
543 L = list(cf.items("section"))
544 L.sort()
545 self.assertEqual(L, expected)
546
Fred Drake8ef67672000-09-27 22:45:25 +0000547
Fred Drakea4923622010-08-09 12:52:45 +0000548class StrictTestCase(BasicTestCase):
549 config_class = configparser.RawConfigParser
550 strict = True
551
552
Georg Brandl96a60ae2010-07-28 13:13:46 +0000553class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000554 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000555
556 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000557 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000558 configparser.ConfigParser: ("something %(with11)s "
559 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000560 configparser.SafeConfigParser: "%(with1)s",
561 }
Fred Drakec6f28912002-10-25 19:40:49 +0000562 cf = self.get_interpolation_config()
563 eq = self.assertEqual
564 eq(cf.get("Foo", "getname"), "Foo")
565 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
566 eq(cf.get("Foo", "bar9"),
567 "something with lots of interpolation (9 steps)")
568 eq(cf.get("Foo", "bar10"),
569 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000570 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Michael Foordbd6c0792010-07-25 23:09:25 +0000571 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000572
Fred Drake54782192002-12-31 06:57:25 +0000573 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000574 rawval = {
575 configparser.ConfigParser: '%(reference)s',
576 configparser.SafeConfigParser: '',
577 }
Fred Drakea4923622010-08-09 12:52:45 +0000578 cf = self.get_interpolation_config()
579 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000580 "Interpolation Error", "name")
581 self.assertEqual(e.reference, "reference")
582 self.assertEqual(e.section, "Interpolation Error")
583 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000584 self.assertEqual(e.args, ('name', 'Interpolation Error',
585 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000586
Fred Drake98e3b292002-10-25 20:42:44 +0000587 def test_items(self):
588 self.check_items_config([('default', '<default>'),
589 ('getdefault', '|<default>|'),
590 ('getname', '|section|'),
591 ('key', '|value|'),
592 ('name', 'value')])
593
David Goodger1cbf2062004-10-03 15:55:09 +0000594 def test_set_nonstring_types(self):
595 cf = self.newconfig()
596 cf.add_section('non-string')
597 cf.set('non-string', 'int', 1)
598 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
599 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
600 '%(list)': '%(list)'})
601 cf.set('non-string', 'string_with_interpolation', '%(list)s')
602 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
603 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
604 self.assertEqual(cf.get('non-string', 'list', raw=True),
605 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
606 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
607 self.assertEqual(cf.get('non-string', 'dict', raw=True),
608 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
609 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
610 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
611 raw=True), '%(list)s')
612 self.assertRaises(ValueError, cf.get, 'non-string',
613 'string_with_interpolation', raw=False)
614
Georg Brandl96a60ae2010-07-28 13:13:46 +0000615class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
616 delimiters = (':=', '$')
617 comment_prefixes = ('//', '"')
618
619class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000620 config_class = configparser.ConfigParser
621 wonderful_spam = ("I'm having spam spam spam spam "
622 "spam spam spam beaked beans spam "
623 "spam spam and spam!").replace(' ', '\t\n')
624
625 def setUp(self):
626 cf = self.newconfig()
627 for i in range(100):
628 s = 'section{}'.format(i)
629 cf.add_section(s)
630 for j in range(10):
631 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
632 with open(support.TESTFN, 'w') as f:
633 cf.write(f)
634
635 def tearDown(self):
636 os.unlink(support.TESTFN)
637
638 def test_dominating_multiline_values(self):
639 # We're reading from file because this is where the code changed
640 # during performance updates in Python 3.2
641 cf_from_file = self.newconfig()
642 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000643 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000644 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
645 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000646
Georg Brandl96a60ae2010-07-28 13:13:46 +0000647class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000648 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000649
650 def test_interpolation(self):
651 cf = self.get_interpolation_config()
652 eq = self.assertEqual
653 eq(cf.get("Foo", "getname"), "%(__name__)s")
654 eq(cf.get("Foo", "bar"),
655 "something %(with1)s interpolation (1 step)")
656 eq(cf.get("Foo", "bar9"),
657 "something %(with9)s lots of interpolation (9 steps)")
658 eq(cf.get("Foo", "bar10"),
659 "something %(with10)s lots of interpolation (10 steps)")
660 eq(cf.get("Foo", "bar11"),
661 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000662
Fred Drake98e3b292002-10-25 20:42:44 +0000663 def test_items(self):
664 self.check_items_config([('default', '<default>'),
665 ('getdefault', '|%(default)s|'),
666 ('getname', '|%(__name__)s|'),
667 ('key', '|%(name)s|'),
668 ('name', 'value')])
669
David Goodger1cbf2062004-10-03 15:55:09 +0000670 def test_set_nonstring_types(self):
671 cf = self.newconfig()
672 cf.add_section('non-string')
673 cf.set('non-string', 'int', 1)
674 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
675 cf.set('non-string', 'dict', {'pi': 3.14159})
676 self.assertEqual(cf.get('non-string', 'int'), 1)
677 self.assertEqual(cf.get('non-string', 'list'),
678 [0, 1, 1, 2, 3, 5, 8, 13])
679 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000680
Georg Brandl96a60ae2010-07-28 13:13:46 +0000681class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
682 delimiters = (':=', '$')
683 comment_prefixes = ('//', '"')
684
685class RawConfigParserTestSambaConf(BasicTestCase):
686 config_class = configparser.RawConfigParser
687 comment_prefixes = ('#', ';', '//', '----')
688 empty_lines_in_values = False
689
690 def test_reading(self):
691 smbconf = support.findfile("cfgparser.2")
692 # check when we pass a mix of readable and non-readable files:
693 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000694 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000695 self.assertEqual(parsed_files, [smbconf])
696 sections = ['global', 'homes', 'printers',
697 'print$', 'pdf-generator', 'tmp', 'Agustin']
698 self.assertEqual(cf.sections(), sections)
699 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
700 self.assertEqual(cf.getint("global", "max log size"), 50)
701 self.assertEqual(cf.get("global", "hosts allow"), "127.")
702 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000703
Fred Drake0eebd5c2002-10-25 21:52:00 +0000704class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000705 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000706
707 def test_safe_interpolation(self):
708 # See http://www.python.org/sf/511737
709 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000710 "option1{eq}xxx\n"
711 "option2{eq}%(option1)s/xxx\n"
712 "ok{eq}%(option1)s/%%s\n"
713 "not_ok{eq}%(option2)s/%%s".format(
714 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000715 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
716 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
717
Guido van Rossumd8faa362007-04-27 19:54:29 +0000718 def test_set_malformatted_interpolation(self):
719 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000720 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000721
722 self.assertEqual(cf.get('sect', "option1"), "foo")
723
724 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
725 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
726 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
727
728 self.assertEqual(cf.get('sect', "option1"), "foo")
729
Georg Brandl1f9fa312009-04-27 16:42:58 +0000730 # bug #5741: double percents are *not* malformed
731 cf.set("sect", "option2", "foo%%bar")
732 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
733
David Goodger1cbf2062004-10-03 15:55:09 +0000734 def test_set_nonstring_types(self):
735 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000736 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000737 # Check that we get a TypeError when setting non-string values
738 # in an existing section:
739 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
740 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
741 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
742 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
743 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
744 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
745
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000746 def test_add_section_default_1(self):
747 cf = self.newconfig()
748 self.assertRaises(ValueError, cf.add_section, "default")
749
750 def test_add_section_default_2(self):
751 cf = self.newconfig()
752 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
753
Georg Brandl96a60ae2010-07-28 13:13:46 +0000754class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
755 delimiters = (':=', '$')
756 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000757
758class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
759 allow_no_value = True
760
Georg Brandl8dcaa732010-07-29 12:17:40 +0000761class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
762 config_class = configparser.SafeConfigParser
763 delimiters = {'='}
764 comment_prefixes = {'#'}
765 allow_no_value = True
766
767 def test_cfgparser_dot_3(self):
768 tricky = support.findfile("cfgparser.3")
769 cf = self.newconfig()
770 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
771 self.assertEqual(cf.sections(), ['strange',
772 'corruption',
773 'yeah, sections can be '
774 'indented as well',
775 'another one!',
776 'no values here',
777 'tricky interpolation',
778 'more interpolation'])
Fred Drakecc645b92010-09-04 04:35:34 +0000779 self.assertEqual(cf.getint('DEFAULT', 'go',
780 vars={'interpolate': '-1'}), -1)
781 with self.assertRaises(ValueError):
782 # no interpolation will happen
783 cf.getint('DEFAULT', 'go', raw=True, vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +0000784 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
785 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
786 longname = 'yeah, sections can be indented as well'
787 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
788 self.assertEquals(cf.get(longname, 'lets use some Unicode'),
789 '片仮名')
790 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
791 # `go` from DEFAULT
792 with self.assertRaises(configparser.InterpolationMissingOptionError):
793 cf.items('no values here')
794 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
795 self.assertEqual(cf.get('tricky interpolation', 'lets'),
796 cf.get('tricky interpolation', 'go'))
797 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
798
799 def test_unicode_failure(self):
800 tricky = support.findfile("cfgparser.3")
801 cf = self.newconfig()
802 with self.assertRaises(UnicodeDecodeError):
803 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000804
Fred Drake88444412010-09-03 04:22:36 +0000805
806class Issue7005TestCase(unittest.TestCase):
807 """Test output when None is set() as a value and allow_no_value == False.
808
809 http://bugs.python.org/issue7005
810
811 """
812
813 expected_output = "[section]\noption = None\n\n"
814
815 def prepare(self, config_class):
816 # This is the default, but that's the point.
817 cp = config_class(allow_no_value=False)
818 cp.add_section("section")
819 cp.set("section", "option", None)
820 sio = io.StringIO()
821 cp.write(sio)
822 return sio.getvalue()
823
824 def test_none_as_value_stringified(self):
825 output = self.prepare(configparser.ConfigParser)
826 self.assertEqual(output, self.expected_output)
827
828 def test_none_as_value_stringified_raw(self):
829 output = self.prepare(configparser.RawConfigParser)
830 self.assertEqual(output, self.expected_output)
831
832
Thomas Wouters89f507f2006-12-13 04:49:30 +0000833class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000834 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000835
836 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +0000837 cf = self.fromstring("[b]\n"
838 "o4=1\n"
839 "o3=2\n"
840 "o2=3\n"
841 "o1=4\n"
842 "[a]\n"
843 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000844 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +0000845 cf.write(output)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000846 self.assertEquals(output.getvalue(),
847 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000848 "k = v\n\n"
Thomas Wouters89f507f2006-12-13 04:49:30 +0000849 "[b]\n"
850 "o1 = 4\n"
851 "o2 = 3\n"
852 "o3 = 2\n"
853 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000854
Fred Drake03c44a32010-02-19 06:08:41 +0000855
Georg Brandl96a60ae2010-07-28 13:13:46 +0000856class CompatibleTestCase(CfgParserTestCaseClass):
857 config_class = configparser.RawConfigParser
Fred Drakecc645b92010-09-04 04:35:34 +0000858 comment_prefixes = configparser._COMPATIBLE
Georg Brandl96a60ae2010-07-28 13:13:46 +0000859
860 def test_comment_handling(self):
861 config_string = textwrap.dedent("""\
862 [Commented Bar]
863 baz=qwe ; a comment
864 foo: bar # not a comment!
865 # but this is a comment
866 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000867 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +0000868 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +0000869 """)
870 cf = self.fromstring(config_string)
871 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
872 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000873 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000874
875
Fred Drakec6f28912002-10-25 19:40:49 +0000876def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000877 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000878 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000879 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000880 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000881 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000882 RawConfigParserTestCaseNonStandardDelimiters,
883 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000884 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000885 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000886 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000887 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000888 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +0000889 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +0000890 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000891 CompatibleTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +0000892 )
893
Fred Drake3af0eb82002-10-25 18:09:24 +0000894
Fred Drakec6f28912002-10-25 19:40:49 +0000895if __name__ == "__main__":
896 test_main()