blob: 5a77bfdfe48c59fbfb44a2fef0a99b2d5194ea2f [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 Drake03c44a32010-02-19 06:08:41 +000033
Fred Drakec6f28912002-10-25 19:40:49 +000034 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000035 arguments = dict(
36 allow_no_value=self.allow_no_value,
37 delimiters=self.delimiters,
38 comment_prefixes=self.comment_prefixes,
39 empty_lines_in_values=self.empty_lines_in_values,
40 dict_type=self.dict_type,
41 )
Fred Drakec6f28912002-10-25 19:40:49 +000042 if defaults is None:
Georg Brandl96a60ae2010-07-28 13:13:46 +000043 self.cf = self.config_class(**arguments)
Fred Drakec6f28912002-10-25 19:40:49 +000044 else:
Fred Drake03c44a32010-02-19 06:08:41 +000045 self.cf = self.config_class(defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000046 **arguments)
Fred Drakec6f28912002-10-25 19:40:49 +000047 return self.cf
Fred Drake8ef67672000-09-27 22:45:25 +000048
Fred Drakec6f28912002-10-25 19:40:49 +000049 def fromstring(self, string, defaults=None):
50 cf = self.newconfig(defaults)
Guido van Rossum34d19282007-08-09 01:03:29 +000051 sio = io.StringIO(string)
Fred Drakec6f28912002-10-25 19:40:49 +000052 cf.readfp(sio)
53 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000054
Georg Brandl96a60ae2010-07-28 13:13:46 +000055class BasicTestCase(CfgParserTestCaseClass):
56
Fred Drakec6f28912002-10-25 19:40:49 +000057 def test_basic(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +000058 config_string = """\
59[Foo Bar]
60foo{0[0]}bar
61[Spacey Bar]
62foo {0[0]} bar
63[Spacey Bar From The Beginning]
64 foo {0[0]} bar
65 baz {0[0]} qwe
66[Commented Bar]
67foo{0[1]} bar {1[1]} comment
68baz{0[0]}qwe {1[0]}another one
69[Long Line]
70foo{0[1]} this line is much, much longer than my editor
71 likes it.
72[Section\\with$weird%characters[\t]
73[Internationalized Stuff]
74foo[bg]{0[1]} Bulgarian
75foo{0[0]}Default
76foo[en]{0[0]}English
77foo[de]{0[0]}Deutsch
78[Spaces]
79key with spaces {0[1]} value
80another with spaces {0[0]} splat!
81""".format(self.delimiters, self.comment_prefixes)
Fred Drake03c44a32010-02-19 06:08:41 +000082 if self.allow_no_value:
83 config_string += (
84 "[NoValue]\n"
85 "option-without-value\n"
86 )
87
88 cf = self.fromstring(config_string)
Fred Drakec6f28912002-10-25 19:40:49 +000089 L = cf.sections()
90 L.sort()
Georg Brandl96a60ae2010-07-28 13:13:46 +000091 E = ['Commented Bar',
92 'Foo Bar',
93 'Internationalized Stuff',
94 'Long Line',
95 'Section\\with$weird%characters[\t',
96 'Spaces',
97 'Spacey Bar',
98 'Spacey Bar From The Beginning',
Fred Drake03c44a32010-02-19 06:08:41 +000099 ]
100 if self.allow_no_value:
101 E.append(r'NoValue')
102 E.sort()
Fred Drakec6f28912002-10-25 19:40:49 +0000103 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +0000104 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +0000105
Fred Drakec6f28912002-10-25 19:40:49 +0000106 # The use of spaces in the section names serves as a
107 # regression test for SourceForge bug #583248:
108 # http://www.python.org/sf/583248
109 eq(cf.get('Foo Bar', 'foo'), 'bar')
110 eq(cf.get('Spacey Bar', 'foo'), 'bar')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000111 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar')
112 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +0000113 eq(cf.get('Commented Bar', 'foo'), 'bar')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000114 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +0000115 eq(cf.get('Spaces', 'key with spaces'), 'value')
116 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drake03c44a32010-02-19 06:08:41 +0000117 if self.allow_no_value:
118 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000119
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000120 self.assertNotIn('__name__', cf.options("Foo Bar"),
121 '__name__ "option" should not be exposed by the API!')
Fred Drakec6f28912002-10-25 19:40:49 +0000122
123 # Make sure the right things happen for remove_option();
124 # added to include check for SourceForge bug #123324:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000125 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000126 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000127 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000128 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000129 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000130 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000131 " that was removed")
132
Michael Foordbd6c0792010-07-25 23:09:25 +0000133 with self.assertRaises(configparser.NoSectionError) as cm:
134 cf.remove_option('No Such Section', 'foo')
135 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000136
137 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000138 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000139
Fred Drakec6f28912002-10-25 19:40:49 +0000140 def test_case_sensitivity(self):
141 cf = self.newconfig()
142 cf.add_section("A")
143 cf.add_section("a")
144 L = cf.sections()
145 L.sort()
146 eq = self.assertEqual
147 eq(L, ["A", "a"])
148 cf.set("a", "B", "value")
149 eq(cf.options("a"), ["b"])
150 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000151 "could not locate option, expecting case-insensitive option names")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000152 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000153 cf.set("A", "A-B", "A-B value")
154 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000155 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000156 cf.has_option("A", opt),
157 "has_option() returned false for option which should exist")
158 eq(cf.options("A"), ["a-b"])
159 eq(cf.options("a"), ["b"])
160 cf.remove_option("a", "B")
161 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000162
Fred Drakec6f28912002-10-25 19:40:49 +0000163 # SF bug #432369:
164 cf = self.fromstring(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000165 "[MySection]\nOption{} first line\n\tsecond line\n".format(
166 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000167 eq(cf.options("MySection"), ["option"])
168 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000169
Fred Drakec6f28912002-10-25 19:40:49 +0000170 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000171 cf = self.fromstring("[section]\n"
172 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000173 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000174 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000175
Fred Drake3c823aa2001-02-26 21:55:34 +0000176
David Goodger68a1abd2004-10-03 15:40:25 +0000177 def test_default_case_sensitivity(self):
178 cf = self.newconfig({"foo": "Bar"})
179 self.assertEqual(
180 cf.get("DEFAULT", "Foo"), "Bar",
181 "could not locate option, expecting case-insensitive option names")
182 cf = self.newconfig({"Foo": "Bar"})
183 self.assertEqual(
184 cf.get("DEFAULT", "Foo"), "Bar",
185 "could not locate option, expecting case-insensitive defaults")
186
Fred Drakec6f28912002-10-25 19:40:49 +0000187 def test_parse_errors(self):
188 self.newconfig()
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000189 self.parse_error(configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000190 "[Foo]\n"
191 "{}val-without-opt-name\n".format(self.delimiters[0]))
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000192 self.parse_error(configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000193 "[Foo]\n"
194 "{}val-without-opt-name\n".format(self.delimiters[1]))
Michael Foordbd6c0792010-07-25 23:09:25 +0000195 e = self.parse_error(configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000196 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000197 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000198 if not self.allow_no_value:
199 e = self.parse_error(configparser.ParsingError,
200 "[Foo]\n wrong-indent\n")
201 self.assertEqual(e.args, ('<???>',))
Fred Drake168bead2001-10-08 17:13:12 +0000202
Fred Drakec6f28912002-10-25 19:40:49 +0000203 def parse_error(self, exc, src):
Guido van Rossum34d19282007-08-09 01:03:29 +0000204 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000205 with self.assertRaises(exc) as cm:
206 self.cf.readfp(sio)
207 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000208
Fred Drakec6f28912002-10-25 19:40:49 +0000209 def test_query_errors(self):
210 cf = self.newconfig()
211 self.assertEqual(cf.sections(), [],
212 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000213 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000214 "new ConfigParser should have no acknowledged "
215 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000216 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000217 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000218 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000219 cf.set("foo", "bar", "value")
220 e = self.get_error(configparser.NoSectionError, "foo", "bar")
221 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000222 cf.add_section("foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000223 e = self.get_error(configparser.NoOptionError, "foo", "bar")
224 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000225
Fred Drakec6f28912002-10-25 19:40:49 +0000226 def get_error(self, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000227 try:
228 self.cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000229 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000230 return e
231 else:
232 self.fail("expected exception type %s.%s"
233 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000234
Fred Drakec6f28912002-10-25 19:40:49 +0000235 def test_boolean(self):
236 cf = self.fromstring(
237 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000238 "T1{equals}1\n"
239 "T2{equals}TRUE\n"
240 "T3{equals}True\n"
241 "T4{equals}oN\n"
242 "T5{equals}yes\n"
243 "F1{equals}0\n"
244 "F2{equals}FALSE\n"
245 "F3{equals}False\n"
246 "F4{equals}oFF\n"
247 "F5{equals}nO\n"
248 "E1{equals}2\n"
249 "E2{equals}foo\n"
250 "E3{equals}-1\n"
251 "E4{equals}0.1\n"
252 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000253 )
254 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000255 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
256 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000257 self.assertRaises(ValueError,
258 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000259
Fred Drakec6f28912002-10-25 19:40:49 +0000260 def test_weird_errors(self):
261 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000262 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000263 with self.assertRaises(configparser.DuplicateSectionError) as cm:
264 cf.add_section("Foo")
265 self.assertEqual(cm.exception.args, ("Foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000266
267 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000268 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000269 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000270 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000271 " likes it.\n"
272 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000273 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000274 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000275 "[Long Line - With Comments!]\n"
276 "test {0[1]} we {comment} can\n"
277 " also {comment} place\n"
278 " comments {comment} in\n"
279 " multiline {comment} values"
280 "\n".format(self.delimiters, comment=self.comment_prefixes[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000281 )
Fred Drake03c44a32010-02-19 06:08:41 +0000282 if self.allow_no_value:
283 config_string += (
284 "[Valueless]\n"
285 "option-without-value\n"
286 )
287
288 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000289 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000290 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000291 expect_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000292 "[DEFAULT]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000293 "foo {equals} another very\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000294 "\tlong line\n"
295 "\n"
296 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000297 "foo {equals} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000298 "\tlikes it.\n"
299 "\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000300 "[Long Line - With Comments!]\n"
301 "test {equals} we\n"
302 "\talso\n"
303 "\tcomments\n"
304 "\tmultiline\n"
305 "\n".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000306 )
Fred Drake03c44a32010-02-19 06:08:41 +0000307 if self.allow_no_value:
308 expect_string += (
309 "[Valueless]\n"
310 "option-without-value\n"
311 "\n"
312 )
313 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000314
Fred Drakeabc086f2004-05-18 03:29:52 +0000315 def test_set_string_types(self):
316 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000317 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000318 # Check that we don't get an exception when setting values in
319 # an existing section using strings:
320 class mystr(str):
321 pass
322 cf.set("sect", "option1", "splat")
323 cf.set("sect", "option1", mystr("splat"))
324 cf.set("sect", "option2", "splat")
325 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000326 cf.set("sect", "option1", "splat")
327 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000328
Fred Drake82903142004-05-18 04:24:02 +0000329 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000330 if self.delimiters[0] != '=':
331 # skip reading the file if we're using an incompatible format
332 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000333 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000334 # check when we pass a mix of readable and non-readable files:
335 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000336 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000337 self.assertEqual(parsed_files, [file1])
338 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
339 # check when we pass only a filename:
340 cf = self.newconfig()
341 parsed_files = cf.read(file1)
342 self.assertEqual(parsed_files, [file1])
343 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
344 # check when we pass only missing files:
345 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000346 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000347 self.assertEqual(parsed_files, [])
348 # check when we pass no files:
349 cf = self.newconfig()
350 parsed_files = cf.read([])
351 self.assertEqual(parsed_files, [])
352
Fred Drakec6f28912002-10-25 19:40:49 +0000353 # shared by subclasses
354 def get_interpolation_config(self):
355 return self.fromstring(
356 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000357 "bar{equals}something %(with1)s interpolation (1 step)\n"
358 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
359 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
360 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
361 "with11{equals}%(with10)s\n"
362 "with10{equals}%(with9)s\n"
363 "with9{equals}%(with8)s\n"
364 "with8{equals}%(With7)s\n"
365 "with7{equals}%(WITH6)s\n"
366 "with6{equals}%(with5)s\n"
367 "With5{equals}%(with4)s\n"
368 "WITH4{equals}%(with3)s\n"
369 "with3{equals}%(with2)s\n"
370 "with2{equals}%(with1)s\n"
371 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000372 "\n"
373 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000374 "foo{equals}%(bar)s\n"
375 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000376 "\n"
377 "[Interpolation Error]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000378 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]),
Fred Drake54782192002-12-31 06:57:25 +0000379 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000380 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000381
Fred Drake98e3b292002-10-25 20:42:44 +0000382 def check_items_config(self, expected):
383 cf = self.fromstring(
384 "[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000385 "name {0[0]} value\n"
386 "key{0[1]} |%(name)s| \n"
387 "getdefault{0[1]} |%(default)s|\n"
388 "getname{0[1]} |%(__name__)s|".format(self.delimiters),
Fred Drake98e3b292002-10-25 20:42:44 +0000389 defaults={"default": "<default>"})
390 L = list(cf.items("section"))
391 L.sort()
392 self.assertEqual(L, expected)
393
Fred Drake8ef67672000-09-27 22:45:25 +0000394
Georg Brandl96a60ae2010-07-28 13:13:46 +0000395class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000396 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000397
398 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000399 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000400 configparser.ConfigParser: ("something %(with11)s "
401 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000402 configparser.SafeConfigParser: "%(with1)s",
403 }
Fred Drakec6f28912002-10-25 19:40:49 +0000404 cf = self.get_interpolation_config()
405 eq = self.assertEqual
406 eq(cf.get("Foo", "getname"), "Foo")
407 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
408 eq(cf.get("Foo", "bar9"),
409 "something with lots of interpolation (9 steps)")
410 eq(cf.get("Foo", "bar10"),
411 "something with lots of interpolation (10 steps)")
Michael Foordbd6c0792010-07-25 23:09:25 +0000412 e = self.get_error(configparser.InterpolationDepthError, "Foo", "bar11")
413 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000414
Fred Drake54782192002-12-31 06:57:25 +0000415 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000416 rawval = {
417 configparser.ConfigParser: '%(reference)s',
418 configparser.SafeConfigParser: '',
419 }
Fred Drake03c44a32010-02-19 06:08:41 +0000420 self.get_interpolation_config()
Michael Foordbd6c0792010-07-25 23:09:25 +0000421 e = self.get_error(configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000422 "Interpolation Error", "name")
423 self.assertEqual(e.reference, "reference")
424 self.assertEqual(e.section, "Interpolation Error")
425 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000426 self.assertEqual(e.args, ('name', 'Interpolation Error',
427 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000428
Fred Drake98e3b292002-10-25 20:42:44 +0000429 def test_items(self):
430 self.check_items_config([('default', '<default>'),
431 ('getdefault', '|<default>|'),
432 ('getname', '|section|'),
433 ('key', '|value|'),
434 ('name', 'value')])
435
David Goodger1cbf2062004-10-03 15:55:09 +0000436 def test_set_nonstring_types(self):
437 cf = self.newconfig()
438 cf.add_section('non-string')
439 cf.set('non-string', 'int', 1)
440 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
441 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
442 '%(list)': '%(list)'})
443 cf.set('non-string', 'string_with_interpolation', '%(list)s')
444 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
445 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
446 self.assertEqual(cf.get('non-string', 'list', raw=True),
447 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
448 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
449 self.assertEqual(cf.get('non-string', 'dict', raw=True),
450 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
451 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
452 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
453 raw=True), '%(list)s')
454 self.assertRaises(ValueError, cf.get, 'non-string',
455 'string_with_interpolation', raw=False)
456
Georg Brandl96a60ae2010-07-28 13:13:46 +0000457class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
458 delimiters = (':=', '$')
459 comment_prefixes = ('//', '"')
460
461class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000462 config_class = configparser.ConfigParser
463 wonderful_spam = ("I'm having spam spam spam spam "
464 "spam spam spam beaked beans spam "
465 "spam spam and spam!").replace(' ', '\t\n')
466
467 def setUp(self):
468 cf = self.newconfig()
469 for i in range(100):
470 s = 'section{}'.format(i)
471 cf.add_section(s)
472 for j in range(10):
473 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
474 with open(support.TESTFN, 'w') as f:
475 cf.write(f)
476
477 def tearDown(self):
478 os.unlink(support.TESTFN)
479
480 def test_dominating_multiline_values(self):
481 # We're reading from file because this is where the code changed
482 # during performance updates in Python 3.2
483 cf_from_file = self.newconfig()
484 with open(support.TESTFN) as f:
485 cf_from_file.readfp(f)
486 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
487 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000488
Georg Brandl96a60ae2010-07-28 13:13:46 +0000489class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000490 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000491
492 def test_interpolation(self):
493 cf = self.get_interpolation_config()
494 eq = self.assertEqual
495 eq(cf.get("Foo", "getname"), "%(__name__)s")
496 eq(cf.get("Foo", "bar"),
497 "something %(with1)s interpolation (1 step)")
498 eq(cf.get("Foo", "bar9"),
499 "something %(with9)s lots of interpolation (9 steps)")
500 eq(cf.get("Foo", "bar10"),
501 "something %(with10)s lots of interpolation (10 steps)")
502 eq(cf.get("Foo", "bar11"),
503 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000504
Fred Drake98e3b292002-10-25 20:42:44 +0000505 def test_items(self):
506 self.check_items_config([('default', '<default>'),
507 ('getdefault', '|%(default)s|'),
508 ('getname', '|%(__name__)s|'),
509 ('key', '|%(name)s|'),
510 ('name', 'value')])
511
David Goodger1cbf2062004-10-03 15:55:09 +0000512 def test_set_nonstring_types(self):
513 cf = self.newconfig()
514 cf.add_section('non-string')
515 cf.set('non-string', 'int', 1)
516 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
517 cf.set('non-string', 'dict', {'pi': 3.14159})
518 self.assertEqual(cf.get('non-string', 'int'), 1)
519 self.assertEqual(cf.get('non-string', 'list'),
520 [0, 1, 1, 2, 3, 5, 8, 13])
521 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000522
Georg Brandl96a60ae2010-07-28 13:13:46 +0000523class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
524 delimiters = (':=', '$')
525 comment_prefixes = ('//', '"')
526
527class RawConfigParserTestSambaConf(BasicTestCase):
528 config_class = configparser.RawConfigParser
529 comment_prefixes = ('#', ';', '//', '----')
530 empty_lines_in_values = False
531
532 def test_reading(self):
533 smbconf = support.findfile("cfgparser.2")
534 # check when we pass a mix of readable and non-readable files:
535 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000536 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000537 self.assertEqual(parsed_files, [smbconf])
538 sections = ['global', 'homes', 'printers',
539 'print$', 'pdf-generator', 'tmp', 'Agustin']
540 self.assertEqual(cf.sections(), sections)
541 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
542 self.assertEqual(cf.getint("global", "max log size"), 50)
543 self.assertEqual(cf.get("global", "hosts allow"), "127.")
544 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000545
Fred Drake0eebd5c2002-10-25 21:52:00 +0000546class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000547 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000548
549 def test_safe_interpolation(self):
550 # See http://www.python.org/sf/511737
551 cf = self.fromstring("[section]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000552 "option1{eq}xxx\n"
553 "option2{eq}%(option1)s/xxx\n"
554 "ok{eq}%(option1)s/%%s\n"
555 "not_ok{eq}%(option2)s/%%s".format(
556 eq=self.delimiters[0]))
Fred Drake0eebd5c2002-10-25 21:52:00 +0000557 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
558 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
559
Guido van Rossumd8faa362007-04-27 19:54:29 +0000560 def test_set_malformatted_interpolation(self):
561 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000562 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000563
564 self.assertEqual(cf.get('sect', "option1"), "foo")
565
566 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
567 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
568 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
569
570 self.assertEqual(cf.get('sect', "option1"), "foo")
571
Georg Brandl1f9fa312009-04-27 16:42:58 +0000572 # bug #5741: double percents are *not* malformed
573 cf.set("sect", "option2", "foo%%bar")
574 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
575
David Goodger1cbf2062004-10-03 15:55:09 +0000576 def test_set_nonstring_types(self):
577 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000578 "option1{eq}foo\n".format(eq=self.delimiters[0]))
David Goodger1cbf2062004-10-03 15:55:09 +0000579 # Check that we get a TypeError when setting non-string values
580 # in an existing section:
581 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
582 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
583 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
584 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
585 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
586 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
587
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000588 def test_add_section_default_1(self):
589 cf = self.newconfig()
590 self.assertRaises(ValueError, cf.add_section, "default")
591
592 def test_add_section_default_2(self):
593 cf = self.newconfig()
594 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
595
Georg Brandl96a60ae2010-07-28 13:13:46 +0000596class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
597 delimiters = (':=', '$')
598 comment_prefixes = ('//', '"')
Fred Drake03c44a32010-02-19 06:08:41 +0000599
600class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
601 allow_no_value = True
602
Georg Brandl8dcaa732010-07-29 12:17:40 +0000603class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
604 config_class = configparser.SafeConfigParser
605 delimiters = {'='}
606 comment_prefixes = {'#'}
607 allow_no_value = True
608
609 def test_cfgparser_dot_3(self):
610 tricky = support.findfile("cfgparser.3")
611 cf = self.newconfig()
612 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
613 self.assertEqual(cf.sections(), ['strange',
614 'corruption',
615 'yeah, sections can be '
616 'indented as well',
617 'another one!',
618 'no values here',
619 'tricky interpolation',
620 'more interpolation'])
621 #self.assertEqual(cf.getint('DEFAULT', 'go', vars={'interpolate': '-1'}),
622 # -1)
623 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
624 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
625 longname = 'yeah, sections can be indented as well'
626 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
627 self.assertEquals(cf.get(longname, 'lets use some Unicode'),
628 '片仮名')
629 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
630 # `go` from DEFAULT
631 with self.assertRaises(configparser.InterpolationMissingOptionError):
632 cf.items('no values here')
633 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
634 self.assertEqual(cf.get('tricky interpolation', 'lets'),
635 cf.get('tricky interpolation', 'go'))
636 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
637
638 def test_unicode_failure(self):
639 tricky = support.findfile("cfgparser.3")
640 cf = self.newconfig()
641 with self.assertRaises(UnicodeDecodeError):
642 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +0000643
Thomas Wouters89f507f2006-12-13 04:49:30 +0000644class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000645 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +0000646
647 def test_sorted(self):
648 self.fromstring("[b]\n"
649 "o4=1\n"
650 "o3=2\n"
651 "o2=3\n"
652 "o1=4\n"
653 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000654 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000655 output = io.StringIO()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000656 self.cf.write(output)
657 self.assertEquals(output.getvalue(),
658 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000659 "k = v\n\n"
Thomas Wouters89f507f2006-12-13 04:49:30 +0000660 "[b]\n"
661 "o1 = 4\n"
662 "o2 = 3\n"
663 "o3 = 2\n"
664 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000665
Fred Drake03c44a32010-02-19 06:08:41 +0000666
Georg Brandl96a60ae2010-07-28 13:13:46 +0000667class CompatibleTestCase(CfgParserTestCaseClass):
668 config_class = configparser.RawConfigParser
669 comment_prefixes = configparser.RawConfigParser._COMPATIBLE
670
671 def test_comment_handling(self):
672 config_string = textwrap.dedent("""\
673 [Commented Bar]
674 baz=qwe ; a comment
675 foo: bar # not a comment!
676 # but this is a comment
677 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +0000678 quirk: this;is not a comment
679 ; a space must precede a comment character
Georg Brandl96a60ae2010-07-28 13:13:46 +0000680 """)
681 cf = self.fromstring(config_string)
682 self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!')
683 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Georg Brandl8dcaa732010-07-29 12:17:40 +0000684 self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000685
686
Fred Drakec6f28912002-10-25 19:40:49 +0000687def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000688 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000689 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000690 ConfigParserTestCaseNonStandardDelimiters,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000691 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000692 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000693 RawConfigParserTestCaseNonStandardDelimiters,
694 RawConfigParserTestSambaConf,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000695 SafeConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000696 SafeConfigParserTestCaseNonStandardDelimiters,
Fred Drake03c44a32010-02-19 06:08:41 +0000697 SafeConfigParserTestCaseNoValue,
Georg Brandl8dcaa732010-07-29 12:17:40 +0000698 SafeConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000699 SortedTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000700 CompatibleTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +0000701 )
702
Fred Drake3af0eb82002-10-25 18:09:24 +0000703
Fred Drakec6f28912002-10-25 19:40:49 +0000704if __name__ == "__main__":
705 test_main()