blob: c5a25954c022f5bdb05fbc713780bf2307249283 [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
Fred Drake8ef67672000-09-27 22:45:25 +00006
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007from test import support
Fred Drake3d5f7e82000-12-04 16:30:40 +00008
Raymond Hettingerf80680d2008-02-06 00:07:11 +00009class SortedDict(collections.UserDict):
Fred Drake03c44a32010-02-19 06:08:41 +000010
Thomas Wouters89f507f2006-12-13 04:49:30 +000011 def items(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000012 return sorted(self.data.items())
Thomas Wouters89f507f2006-12-13 04:49:30 +000013
14 def keys(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000015 return sorted(self.data.keys())
Thomas Wouters9fe394c2007-02-05 01:24:16 +000016
Thomas Wouters89f507f2006-12-13 04:49:30 +000017 def values(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000018 return [i[1] for i in self.items()]
Thomas Wouters89f507f2006-12-13 04:49:30 +000019
20 def iteritems(self): return iter(self.items())
21 def iterkeys(self): return iter(self.keys())
22 __iter__ = iterkeys
23 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000024
Fred Drake03c44a32010-02-19 06:08:41 +000025
Fred Drakec6f28912002-10-25 19:40:49 +000026class TestCaseBase(unittest.TestCase):
Fred Drake03c44a32010-02-19 06:08:41 +000027 allow_no_value = False
28
Fred Drakec6f28912002-10-25 19:40:49 +000029 def newconfig(self, defaults=None):
30 if defaults is None:
Fred Drake03c44a32010-02-19 06:08:41 +000031 self.cf = self.config_class(allow_no_value=self.allow_no_value)
Fred Drakec6f28912002-10-25 19:40:49 +000032 else:
Fred Drake03c44a32010-02-19 06:08:41 +000033 self.cf = self.config_class(defaults,
34 allow_no_value=self.allow_no_value)
Fred Drakec6f28912002-10-25 19:40:49 +000035 return self.cf
Fred Drake8ef67672000-09-27 22:45:25 +000036
Fred Drakec6f28912002-10-25 19:40:49 +000037 def fromstring(self, string, defaults=None):
38 cf = self.newconfig(defaults)
Guido van Rossum34d19282007-08-09 01:03:29 +000039 sio = io.StringIO(string)
Fred Drakec6f28912002-10-25 19:40:49 +000040 cf.readfp(sio)
41 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000042
Fred Drakec6f28912002-10-25 19:40:49 +000043 def test_basic(self):
Fred Drake03c44a32010-02-19 06:08:41 +000044 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +000045 "[Foo Bar]\n"
46 "foo=bar\n"
47 "[Spacey Bar]\n"
48 "foo = bar\n"
49 "[Commented Bar]\n"
50 "foo: bar ; comment\n"
51 "[Long Line]\n"
52 "foo: this line is much, much longer than my editor\n"
53 " likes it.\n"
54 "[Section\\with$weird%characters[\t]\n"
55 "[Internationalized Stuff]\n"
56 "foo[bg]: Bulgarian\n"
57 "foo=Default\n"
58 "foo[en]=English\n"
59 "foo[de]=Deutsch\n"
60 "[Spaces]\n"
61 "key with spaces : value\n"
62 "another with spaces = splat!\n"
63 )
Fred Drake03c44a32010-02-19 06:08:41 +000064 if self.allow_no_value:
65 config_string += (
66 "[NoValue]\n"
67 "option-without-value\n"
68 )
69
70 cf = self.fromstring(config_string)
Fred Drakec6f28912002-10-25 19:40:49 +000071 L = cf.sections()
72 L.sort()
Fred Drake03c44a32010-02-19 06:08:41 +000073 E = [r'Commented Bar',
74 r'Foo Bar',
75 r'Internationalized Stuff',
76 r'Long Line',
77 r'Section\with$weird%characters[' '\t',
78 r'Spaces',
79 r'Spacey Bar',
80 ]
81 if self.allow_no_value:
82 E.append(r'NoValue')
83 E.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000084 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000085 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000086
Fred Drakec6f28912002-10-25 19:40:49 +000087 # The use of spaces in the section names serves as a
88 # regression test for SourceForge bug #583248:
89 # http://www.python.org/sf/583248
90 eq(cf.get('Foo Bar', 'foo'), 'bar')
91 eq(cf.get('Spacey Bar', 'foo'), 'bar')
92 eq(cf.get('Commented Bar', 'foo'), 'bar')
93 eq(cf.get('Spaces', 'key with spaces'), 'value')
94 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drake03c44a32010-02-19 06:08:41 +000095 if self.allow_no_value:
96 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +000097
Ezio Melottib58e0bd2010-01-23 15:40:09 +000098 self.assertNotIn('__name__', cf.options("Foo Bar"),
99 '__name__ "option" should not be exposed by the API!')
Fred Drakec6f28912002-10-25 19:40:49 +0000100
101 # Make sure the right things happen for remove_option();
102 # added to include check for SourceForge bug #123324:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000103 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000104 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000105 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000106 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000107 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000108 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000109 " that was removed")
110
Michael Foordbd6c0792010-07-25 23:09:25 +0000111 with self.assertRaises(configparser.NoSectionError) as cm:
112 cf.remove_option('No Such Section', 'foo')
113 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000114
115 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000116 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000117
Fred Drakec6f28912002-10-25 19:40:49 +0000118 def test_case_sensitivity(self):
119 cf = self.newconfig()
120 cf.add_section("A")
121 cf.add_section("a")
122 L = cf.sections()
123 L.sort()
124 eq = self.assertEqual
125 eq(L, ["A", "a"])
126 cf.set("a", "B", "value")
127 eq(cf.options("a"), ["b"])
128 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000129 "could not locate option, expecting case-insensitive option names")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000130 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000131 cf.set("A", "A-B", "A-B value")
132 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000133 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000134 cf.has_option("A", opt),
135 "has_option() returned false for option which should exist")
136 eq(cf.options("A"), ["a-b"])
137 eq(cf.options("a"), ["b"])
138 cf.remove_option("a", "B")
139 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000140
Fred Drakec6f28912002-10-25 19:40:49 +0000141 # SF bug #432369:
142 cf = self.fromstring(
143 "[MySection]\nOption: first line\n\tsecond line\n")
144 eq(cf.options("MySection"), ["option"])
145 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000146
Fred Drakec6f28912002-10-25 19:40:49 +0000147 # SF bug #561822:
148 cf = self.fromstring("[section]\nnekey=nevalue\n",
149 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000150 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000151
Fred Drake3c823aa2001-02-26 21:55:34 +0000152
David Goodger68a1abd2004-10-03 15:40:25 +0000153 def test_default_case_sensitivity(self):
154 cf = self.newconfig({"foo": "Bar"})
155 self.assertEqual(
156 cf.get("DEFAULT", "Foo"), "Bar",
157 "could not locate option, expecting case-insensitive option names")
158 cf = self.newconfig({"Foo": "Bar"})
159 self.assertEqual(
160 cf.get("DEFAULT", "Foo"), "Bar",
161 "could not locate option, expecting case-insensitive defaults")
162
Fred Drakec6f28912002-10-25 19:40:49 +0000163 def test_parse_errors(self):
164 self.newconfig()
Michael Foordbd6c0792010-07-25 23:09:25 +0000165 e = self.parse_error(configparser.ParsingError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000166 "[Foo]\n extra-spaces: splat\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000167 self.assertEqual(e.args, ('<???>',))
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000168 self.parse_error(configparser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000169 "[Foo]\n extra-spaces= splat\n")
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000170 self.parse_error(configparser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000171 "[Foo]\n:value-without-option-name\n")
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000172 self.parse_error(configparser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000173 "[Foo]\n=value-without-option-name\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000174 e = self.parse_error(configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000175 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000176 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Fred Drake168bead2001-10-08 17:13:12 +0000177
Fred Drakec6f28912002-10-25 19:40:49 +0000178 def parse_error(self, exc, src):
Guido van Rossum34d19282007-08-09 01:03:29 +0000179 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000180 with self.assertRaises(exc) as cm:
181 self.cf.readfp(sio)
182 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000183
Fred Drakec6f28912002-10-25 19:40:49 +0000184 def test_query_errors(self):
185 cf = self.newconfig()
186 self.assertEqual(cf.sections(), [],
187 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000188 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000189 "new ConfigParser should have no acknowledged "
190 "sections")
Michael Foordbd6c0792010-07-25 23:09:25 +0000191 with self.assertRaises(configparser.NoSectionError) as cm:
192 cf.options("Foo")
193 with self.assertRaises(configparser.NoSectionError) as cm:
194 cf.set("foo", "bar", "value")
195 e = self.get_error(configparser.NoSectionError, "foo", "bar")
196 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000197 cf.add_section("foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000198 e = self.get_error(configparser.NoOptionError, "foo", "bar")
199 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000200
Fred Drakec6f28912002-10-25 19:40:49 +0000201 def get_error(self, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000202 try:
203 self.cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000204 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000205 return e
206 else:
207 self.fail("expected exception type %s.%s"
208 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000209
Fred Drakec6f28912002-10-25 19:40:49 +0000210 def test_boolean(self):
211 cf = self.fromstring(
212 "[BOOLTEST]\n"
213 "T1=1\n"
214 "T2=TRUE\n"
215 "T3=True\n"
216 "T4=oN\n"
217 "T5=yes\n"
218 "F1=0\n"
219 "F2=FALSE\n"
220 "F3=False\n"
221 "F4=oFF\n"
222 "F5=nO\n"
223 "E1=2\n"
224 "E2=foo\n"
225 "E3=-1\n"
226 "E4=0.1\n"
227 "E5=FALSE AND MORE"
228 )
229 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000230 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
231 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000232 self.assertRaises(ValueError,
233 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000234
Fred Drakec6f28912002-10-25 19:40:49 +0000235 def test_weird_errors(self):
236 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000237 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000238 with self.assertRaises(configparser.DuplicateSectionError) as cm:
239 cf.add_section("Foo")
240 self.assertEqual(cm.exception.args, ("Foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000241
242 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000243 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000244 "[Long Line]\n"
245 "foo: this line is much, much longer than my editor\n"
246 " likes it.\n"
247 "[DEFAULT]\n"
248 "foo: another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000249 " long line\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000250 )
Fred Drake03c44a32010-02-19 06:08:41 +0000251 if self.allow_no_value:
252 config_string += (
253 "[Valueless]\n"
254 "option-without-value\n"
255 )
256
257 cf = self.fromstring(config_string)
Guido van Rossum34d19282007-08-09 01:03:29 +0000258 output = io.StringIO()
Fred Drakec6f28912002-10-25 19:40:49 +0000259 cf.write(output)
Fred Drake03c44a32010-02-19 06:08:41 +0000260 expect_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000261 "[DEFAULT]\n"
262 "foo = another very\n"
263 "\tlong line\n"
264 "\n"
265 "[Long Line]\n"
266 "foo = this line is much, much longer than my editor\n"
267 "\tlikes it.\n"
268 "\n"
269 )
Fred Drake03c44a32010-02-19 06:08:41 +0000270 if self.allow_no_value:
271 expect_string += (
272 "[Valueless]\n"
273 "option-without-value\n"
274 "\n"
275 )
276 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000277
Fred Drakeabc086f2004-05-18 03:29:52 +0000278 def test_set_string_types(self):
279 cf = self.fromstring("[sect]\n"
280 "option1=foo\n")
281 # Check that we don't get an exception when setting values in
282 # an existing section using strings:
283 class mystr(str):
284 pass
285 cf.set("sect", "option1", "splat")
286 cf.set("sect", "option1", mystr("splat"))
287 cf.set("sect", "option2", "splat")
288 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000289 cf.set("sect", "option1", "splat")
290 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000291
Fred Drake82903142004-05-18 04:24:02 +0000292 def test_read_returns_file_list(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000293 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000294 # check when we pass a mix of readable and non-readable files:
295 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000296 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000297 self.assertEqual(parsed_files, [file1])
298 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
299 # check when we pass only a filename:
300 cf = self.newconfig()
301 parsed_files = cf.read(file1)
302 self.assertEqual(parsed_files, [file1])
303 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
304 # check when we pass only missing files:
305 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000306 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000307 self.assertEqual(parsed_files, [])
308 # check when we pass no files:
309 cf = self.newconfig()
310 parsed_files = cf.read([])
311 self.assertEqual(parsed_files, [])
312
Fred Drakec6f28912002-10-25 19:40:49 +0000313 # shared by subclasses
314 def get_interpolation_config(self):
315 return self.fromstring(
316 "[Foo]\n"
317 "bar=something %(with1)s interpolation (1 step)\n"
318 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
319 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
320 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
321 "with11=%(with10)s\n"
322 "with10=%(with9)s\n"
323 "with9=%(with8)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000324 "with8=%(With7)s\n"
325 "with7=%(WITH6)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000326 "with6=%(with5)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000327 "With5=%(with4)s\n"
328 "WITH4=%(with3)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000329 "with3=%(with2)s\n"
330 "with2=%(with1)s\n"
331 "with1=with\n"
332 "\n"
333 "[Mutual Recursion]\n"
334 "foo=%(bar)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000335 "bar=%(foo)s\n"
336 "\n"
337 "[Interpolation Error]\n"
338 "name=%(reference)s\n",
339 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000340 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000341
Fred Drake98e3b292002-10-25 20:42:44 +0000342 def check_items_config(self, expected):
343 cf = self.fromstring(
344 "[section]\n"
345 "name = value\n"
346 "key: |%(name)s| \n"
347 "getdefault: |%(default)s|\n"
348 "getname: |%(__name__)s|",
349 defaults={"default": "<default>"})
350 L = list(cf.items("section"))
351 L.sort()
352 self.assertEqual(L, expected)
353
Fred Drake8ef67672000-09-27 22:45:25 +0000354
Fred Drakec6f28912002-10-25 19:40:49 +0000355class ConfigParserTestCase(TestCaseBase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000356 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000357
358 def test_interpolation(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000359 rawval = {
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000360 configparser.ConfigParser: ("something %(with11)s "
361 "lots of interpolation (11 steps)"),
Michael Foordbd6c0792010-07-25 23:09:25 +0000362 configparser.SafeConfigParser: "%(with1)s",
363 }
Fred Drakec6f28912002-10-25 19:40:49 +0000364 cf = self.get_interpolation_config()
365 eq = self.assertEqual
366 eq(cf.get("Foo", "getname"), "Foo")
367 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
368 eq(cf.get("Foo", "bar9"),
369 "something with lots of interpolation (9 steps)")
370 eq(cf.get("Foo", "bar10"),
371 "something with lots of interpolation (10 steps)")
Michael Foordbd6c0792010-07-25 23:09:25 +0000372 e = self.get_error(configparser.InterpolationDepthError, "Foo", "bar11")
373 self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
Fred Drake95b96d32001-02-12 17:23:20 +0000374
Fred Drake54782192002-12-31 06:57:25 +0000375 def test_interpolation_missing_value(self):
Michael Foordbd6c0792010-07-25 23:09:25 +0000376 rawval = {
377 configparser.ConfigParser: '%(reference)s',
378 configparser.SafeConfigParser: '',
379 }
Fred Drake03c44a32010-02-19 06:08:41 +0000380 self.get_interpolation_config()
Michael Foordbd6c0792010-07-25 23:09:25 +0000381 e = self.get_error(configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000382 "Interpolation Error", "name")
383 self.assertEqual(e.reference, "reference")
384 self.assertEqual(e.section, "Interpolation Error")
385 self.assertEqual(e.option, "name")
Michael Foordbd6c0792010-07-25 23:09:25 +0000386 self.assertEqual(e.args, ('name', 'Interpolation Error',
387 rawval[self.config_class], 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000388
Fred Drake98e3b292002-10-25 20:42:44 +0000389 def test_items(self):
390 self.check_items_config([('default', '<default>'),
391 ('getdefault', '|<default>|'),
392 ('getname', '|section|'),
393 ('key', '|value|'),
394 ('name', 'value')])
395
David Goodger1cbf2062004-10-03 15:55:09 +0000396 def test_set_nonstring_types(self):
397 cf = self.newconfig()
398 cf.add_section('non-string')
399 cf.set('non-string', 'int', 1)
400 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
401 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
402 '%(list)': '%(list)'})
403 cf.set('non-string', 'string_with_interpolation', '%(list)s')
404 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
405 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
406 self.assertEqual(cf.get('non-string', 'list', raw=True),
407 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
408 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
409 self.assertEqual(cf.get('non-string', 'dict', raw=True),
410 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
411 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
412 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
413 raw=True), '%(list)s')
414 self.assertRaises(ValueError, cf.get, 'non-string',
415 'string_with_interpolation', raw=False)
416
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000417class MultilineValuesTestCase(TestCaseBase):
418 config_class = configparser.ConfigParser
419 wonderful_spam = ("I'm having spam spam spam spam "
420 "spam spam spam beaked beans spam "
421 "spam spam and spam!").replace(' ', '\t\n')
422
423 def setUp(self):
424 cf = self.newconfig()
425 for i in range(100):
426 s = 'section{}'.format(i)
427 cf.add_section(s)
428 for j in range(10):
429 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
430 with open(support.TESTFN, 'w') as f:
431 cf.write(f)
432
433 def tearDown(self):
434 os.unlink(support.TESTFN)
435
436 def test_dominating_multiline_values(self):
437 # We're reading from file because this is where the code changed
438 # during performance updates in Python 3.2
439 cf_from_file = self.newconfig()
440 with open(support.TESTFN) as f:
441 cf_from_file.readfp(f)
442 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
443 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000444
Fred Drakec6f28912002-10-25 19:40:49 +0000445class RawConfigParserTestCase(TestCaseBase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000446 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000447
448 def test_interpolation(self):
449 cf = self.get_interpolation_config()
450 eq = self.assertEqual
451 eq(cf.get("Foo", "getname"), "%(__name__)s")
452 eq(cf.get("Foo", "bar"),
453 "something %(with1)s interpolation (1 step)")
454 eq(cf.get("Foo", "bar9"),
455 "something %(with9)s lots of interpolation (9 steps)")
456 eq(cf.get("Foo", "bar10"),
457 "something %(with10)s lots of interpolation (10 steps)")
458 eq(cf.get("Foo", "bar11"),
459 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000460
Fred Drake98e3b292002-10-25 20:42:44 +0000461 def test_items(self):
462 self.check_items_config([('default', '<default>'),
463 ('getdefault', '|%(default)s|'),
464 ('getname', '|%(__name__)s|'),
465 ('key', '|%(name)s|'),
466 ('name', 'value')])
467
David Goodger1cbf2062004-10-03 15:55:09 +0000468 def test_set_nonstring_types(self):
469 cf = self.newconfig()
470 cf.add_section('non-string')
471 cf.set('non-string', 'int', 1)
472 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
473 cf.set('non-string', 'dict', {'pi': 3.14159})
474 self.assertEqual(cf.get('non-string', 'int'), 1)
475 self.assertEqual(cf.get('non-string', 'list'),
476 [0, 1, 1, 2, 3, 5, 8, 13])
477 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000478
Fred Drake8ef67672000-09-27 22:45:25 +0000479
Fred Drake0eebd5c2002-10-25 21:52:00 +0000480class SafeConfigParserTestCase(ConfigParserTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000481 config_class = configparser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000482
483 def test_safe_interpolation(self):
484 # See http://www.python.org/sf/511737
485 cf = self.fromstring("[section]\n"
486 "option1=xxx\n"
487 "option2=%(option1)s/xxx\n"
488 "ok=%(option1)s/%%s\n"
489 "not_ok=%(option2)s/%%s")
490 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
491 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
492
Guido van Rossumd8faa362007-04-27 19:54:29 +0000493 def test_set_malformatted_interpolation(self):
494 cf = self.fromstring("[sect]\n"
495 "option1=foo\n")
496
497 self.assertEqual(cf.get('sect', "option1"), "foo")
498
499 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
500 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
501 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
502
503 self.assertEqual(cf.get('sect', "option1"), "foo")
504
Georg Brandl1f9fa312009-04-27 16:42:58 +0000505 # bug #5741: double percents are *not* malformed
506 cf.set("sect", "option2", "foo%%bar")
507 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
508
David Goodger1cbf2062004-10-03 15:55:09 +0000509 def test_set_nonstring_types(self):
510 cf = self.fromstring("[sect]\n"
511 "option1=foo\n")
512 # Check that we get a TypeError when setting non-string values
513 # in an existing section:
514 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
515 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
516 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
517 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
518 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
519 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
520
Christian Heimes90c3d9b2008-02-23 13:18:03 +0000521 def test_add_section_default_1(self):
522 cf = self.newconfig()
523 self.assertRaises(ValueError, cf.add_section, "default")
524
525 def test_add_section_default_2(self):
526 cf = self.newconfig()
527 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
528
Fred Drake03c44a32010-02-19 06:08:41 +0000529
530class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
531 allow_no_value = True
532
533
Thomas Wouters89f507f2006-12-13 04:49:30 +0000534class SortedTestCase(RawConfigParserTestCase):
535 def newconfig(self, defaults=None):
536 self.cf = self.config_class(defaults=defaults, dict_type=SortedDict)
537 return self.cf
538
539 def test_sorted(self):
540 self.fromstring("[b]\n"
541 "o4=1\n"
542 "o3=2\n"
543 "o2=3\n"
544 "o1=4\n"
545 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000546 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +0000547 output = io.StringIO()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000548 self.cf.write(output)
549 self.assertEquals(output.getvalue(),
550 "[a]\n"
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000551 "k = v\n\n"
Thomas Wouters89f507f2006-12-13 04:49:30 +0000552 "[b]\n"
553 "o1 = 4\n"
554 "o2 = 3\n"
555 "o3 = 2\n"
556 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000557
Fred Drake03c44a32010-02-19 06:08:41 +0000558
Fred Drakec6f28912002-10-25 19:40:49 +0000559def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000560 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +0000561 ConfigParserTestCase,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000562 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000563 RawConfigParserTestCase,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000564 SafeConfigParserTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +0000565 SafeConfigParserTestCaseNoValue,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000566 SortedTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +0000567 )
568
Fred Drake3af0eb82002-10-25 18:09:24 +0000569
Fred Drakec6f28912002-10-25 19:40:49 +0000570if __name__ == "__main__":
571 test_main()