blob: 906e9cf12321da227e9a4b17965765d8d3732835 [file] [log] [blame]
Georg Brandl392c6fc2008-05-25 07:25:25 +00001import ConfigParser
Fred Drake8ef67672000-09-27 22:45:25 +00002import StringIO
Brian Curtine4334b42010-07-26 02:30:15 +00003import os
Fred Drakec6f28912002-10-25 19:40:49 +00004import unittest
Martin v. Löwisa00bcac2006-12-03 12:01:53 +00005import UserDict
Fred Drake8ef67672000-09-27 22:45:25 +00006
Fred Drakec6f28912002-10-25 19:40:49 +00007from test import test_support
Fred Drake3d5f7e82000-12-04 16:30:40 +00008
Fred Drakecc43b562010-02-19 05:24:30 +00009
Martin v. Löwisa00bcac2006-12-03 12:01:53 +000010class SortedDict(UserDict.UserDict):
11 def items(self):
12 result = self.data.items()
13 result.sort()
14 return result
15
16 def keys(self):
17 result = self.data.keys()
18 result.sort()
19 return result
Tim Petersf733abb2007-01-30 03:03:46 +000020
Martin v. Löwisa00bcac2006-12-03 12:01:53 +000021 def values(self):
Georg Brandlcd4a21b2010-02-06 23:34:10 +000022 # XXX never used?
Martin v. Löwisa00bcac2006-12-03 12:01:53 +000023 result = self.items()
Georg Brandlcd4a21b2010-02-06 23:34:10 +000024 return [i[1] for i in result]
Martin v. Löwisa00bcac2006-12-03 12:01:53 +000025
26 def iteritems(self): return iter(self.items())
27 def iterkeys(self): return iter(self.keys())
28 __iter__ = iterkeys
29 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000030
Fred Drakecc43b562010-02-19 05:24:30 +000031
Fred Drakec6f28912002-10-25 19:40:49 +000032class TestCaseBase(unittest.TestCase):
Fred Drakecc43b562010-02-19 05:24:30 +000033 allow_no_value = False
34
Fred Drakec6f28912002-10-25 19:40:49 +000035 def newconfig(self, defaults=None):
36 if defaults is None:
Fred Drakecc43b562010-02-19 05:24:30 +000037 self.cf = self.config_class(allow_no_value=self.allow_no_value)
Fred Drakec6f28912002-10-25 19:40:49 +000038 else:
Fred Drakecc43b562010-02-19 05:24:30 +000039 self.cf = self.config_class(defaults,
40 allow_no_value=self.allow_no_value)
Fred Drakec6f28912002-10-25 19:40:49 +000041 return self.cf
Fred Drake8ef67672000-09-27 22:45:25 +000042
Fred Drakec6f28912002-10-25 19:40:49 +000043 def fromstring(self, string, defaults=None):
44 cf = self.newconfig(defaults)
45 sio = StringIO.StringIO(string)
46 cf.readfp(sio)
47 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000048
Fred Drakec6f28912002-10-25 19:40:49 +000049 def test_basic(self):
Fred Drakecc43b562010-02-19 05:24:30 +000050 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +000051 "[Foo Bar]\n"
52 "foo=bar\n"
53 "[Spacey Bar]\n"
54 "foo = bar\n"
55 "[Commented Bar]\n"
56 "foo: bar ; comment\n"
57 "[Long Line]\n"
58 "foo: this line is much, much longer than my editor\n"
59 " likes it.\n"
60 "[Section\\with$weird%characters[\t]\n"
61 "[Internationalized Stuff]\n"
62 "foo[bg]: Bulgarian\n"
63 "foo=Default\n"
64 "foo[en]=English\n"
65 "foo[de]=Deutsch\n"
66 "[Spaces]\n"
67 "key with spaces : value\n"
68 "another with spaces = splat!\n"
69 )
Fred Drakecc43b562010-02-19 05:24:30 +000070 if self.allow_no_value:
71 config_string += (
72 "[NoValue]\n"
73 "option-without-value\n"
74 )
75
76 cf = self.fromstring(config_string)
Fred Drakec6f28912002-10-25 19:40:49 +000077 L = cf.sections()
78 L.sort()
Fred Drakecc43b562010-02-19 05:24:30 +000079 E = [r'Commented Bar',
80 r'Foo Bar',
81 r'Internationalized Stuff',
82 r'Long Line',
83 r'Section\with$weird%characters[' '\t',
84 r'Spaces',
85 r'Spacey Bar',
86 ]
87 if self.allow_no_value:
88 E.append(r'NoValue')
89 E.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000090 eq = self.assertEqual
Fred Drakecc43b562010-02-19 05:24:30 +000091 eq(L, E)
Fred Drake8ef67672000-09-27 22:45:25 +000092
Fred Drakec6f28912002-10-25 19:40:49 +000093 # The use of spaces in the section names serves as a
94 # regression test for SourceForge bug #583248:
95 # http://www.python.org/sf/583248
96 eq(cf.get('Foo Bar', 'foo'), 'bar')
97 eq(cf.get('Spacey Bar', 'foo'), 'bar')
98 eq(cf.get('Commented Bar', 'foo'), 'bar')
99 eq(cf.get('Spaces', 'key with spaces'), 'value')
100 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc43b562010-02-19 05:24:30 +0000101 if self.allow_no_value:
102 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000103
Ezio Melottiaa980582010-01-23 23:04:36 +0000104 self.assertNotIn('__name__', cf.options("Foo Bar"),
105 '__name__ "option" should not be exposed by the API!')
Fred Drakec6f28912002-10-25 19:40:49 +0000106
107 # Make sure the right things happen for remove_option();
108 # added to include check for SourceForge bug #123324:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000109 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson3e4caeb2009-02-21 20:27:01 +0000110 "remove_option() failed to report existence of option")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000111 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000112 "remove_option() failed to remove option")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000113 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson3e4caeb2009-02-21 20:27:01 +0000114 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000115 " that was removed")
116
Georg Brandl392c6fc2008-05-25 07:25:25 +0000117 self.assertRaises(ConfigParser.NoSectionError,
Fred Drakec6f28912002-10-25 19:40:49 +0000118 cf.remove_option, 'No Such Section', 'foo')
119
120 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000121 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000122
Fred Drakec6f28912002-10-25 19:40:49 +0000123 def test_case_sensitivity(self):
124 cf = self.newconfig()
125 cf.add_section("A")
126 cf.add_section("a")
127 L = cf.sections()
128 L.sort()
129 eq = self.assertEqual
130 eq(L, ["A", "a"])
131 cf.set("a", "B", "value")
132 eq(cf.options("a"), ["b"])
133 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000134 "could not locate option, expecting case-insensitive option names")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000135 self.assertTrue(cf.has_option("a", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000136 cf.set("A", "A-B", "A-B value")
137 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000138 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000139 cf.has_option("A", opt),
140 "has_option() returned false for option which should exist")
141 eq(cf.options("A"), ["a-b"])
142 eq(cf.options("a"), ["b"])
143 cf.remove_option("a", "B")
144 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000145
Fred Drakec6f28912002-10-25 19:40:49 +0000146 # SF bug #432369:
147 cf = self.fromstring(
148 "[MySection]\nOption: first line\n\tsecond line\n")
149 eq(cf.options("MySection"), ["option"])
150 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000151
Fred Drakec6f28912002-10-25 19:40:49 +0000152 # SF bug #561822:
153 cf = self.fromstring("[section]\nnekey=nevalue\n",
154 defaults={"key":"value"})
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000155 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000156
Fred Drake3c823aa2001-02-26 21:55:34 +0000157
David Goodger68a1abd2004-10-03 15:40:25 +0000158 def test_default_case_sensitivity(self):
159 cf = self.newconfig({"foo": "Bar"})
160 self.assertEqual(
161 cf.get("DEFAULT", "Foo"), "Bar",
162 "could not locate option, expecting case-insensitive option names")
163 cf = self.newconfig({"Foo": "Bar"})
164 self.assertEqual(
165 cf.get("DEFAULT", "Foo"), "Bar",
166 "could not locate option, expecting case-insensitive defaults")
167
Fred Drakec6f28912002-10-25 19:40:49 +0000168 def test_parse_errors(self):
169 self.newconfig()
Georg Brandl392c6fc2008-05-25 07:25:25 +0000170 self.parse_error(ConfigParser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000171 "[Foo]\n extra-spaces: splat\n")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000172 self.parse_error(ConfigParser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000173 "[Foo]\n extra-spaces= splat\n")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000174 self.parse_error(ConfigParser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000175 "[Foo]\n:value-without-option-name\n")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000176 self.parse_error(ConfigParser.ParsingError,
Fred Drakec6f28912002-10-25 19:40:49 +0000177 "[Foo]\n=value-without-option-name\n")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000178 self.parse_error(ConfigParser.MissingSectionHeaderError,
Fred Drakec6f28912002-10-25 19:40:49 +0000179 "No Section!\n")
Fred Drake168bead2001-10-08 17:13:12 +0000180
Fred Drakec6f28912002-10-25 19:40:49 +0000181 def parse_error(self, exc, src):
182 sio = StringIO.StringIO(src)
183 self.assertRaises(exc, self.cf.readfp, sio)
Fred Drake168bead2001-10-08 17:13:12 +0000184
Fred Drakec6f28912002-10-25 19:40:49 +0000185 def test_query_errors(self):
186 cf = self.newconfig()
187 self.assertEqual(cf.sections(), [],
188 "new ConfigParser should have no defined sections")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000189 self.assertFalse(cf.has_section("Foo"),
Brian Curtine4334b42010-07-26 02:30:15 +0000190 "new ConfigParser should have no acknowledged "
191 "sections")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000192 self.assertRaises(ConfigParser.NoSectionError,
Fred Drakec6f28912002-10-25 19:40:49 +0000193 cf.options, "Foo")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000194 self.assertRaises(ConfigParser.NoSectionError,
Fred Drakec6f28912002-10-25 19:40:49 +0000195 cf.set, "foo", "bar", "value")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000196 self.get_error(ConfigParser.NoSectionError, "foo", "bar")
Fred Drakec6f28912002-10-25 19:40:49 +0000197 cf.add_section("foo")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000198 self.get_error(ConfigParser.NoOptionError, "foo", "bar")
Fred Drake8ef67672000-09-27 22:45:25 +0000199
Fred Drakec6f28912002-10-25 19:40:49 +0000200 def get_error(self, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000201 try:
202 self.cf.get(section, option)
203 except exc, e:
204 return e
205 else:
206 self.fail("expected exception type %s.%s"
207 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000208
Fred Drakec6f28912002-10-25 19:40:49 +0000209 def test_boolean(self):
210 cf = self.fromstring(
211 "[BOOLTEST]\n"
212 "T1=1\n"
213 "T2=TRUE\n"
214 "T3=True\n"
215 "T4=oN\n"
216 "T5=yes\n"
217 "F1=0\n"
218 "F2=FALSE\n"
219 "F3=False\n"
220 "F4=oFF\n"
221 "F5=nO\n"
222 "E1=2\n"
223 "E2=foo\n"
224 "E3=-1\n"
225 "E4=0.1\n"
226 "E5=FALSE AND MORE"
227 )
228 for x in range(1, 5):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000229 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
230 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000231 self.assertRaises(ValueError,
232 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000233
Fred Drakec6f28912002-10-25 19:40:49 +0000234 def test_weird_errors(self):
235 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000236 cf.add_section("Foo")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000237 self.assertRaises(ConfigParser.DuplicateSectionError,
Fred Drakec6f28912002-10-25 19:40:49 +0000238 cf.add_section, "Foo")
239
240 def test_write(self):
Fred Drakecc43b562010-02-19 05:24:30 +0000241 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000242 "[Long Line]\n"
243 "foo: this line is much, much longer than my editor\n"
244 " likes it.\n"
245 "[DEFAULT]\n"
246 "foo: another very\n"
Fred Drakecc43b562010-02-19 05:24:30 +0000247 " long line\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000248 )
Fred Drakecc43b562010-02-19 05:24:30 +0000249 if self.allow_no_value:
250 config_string += (
251 "[Valueless]\n"
252 "option-without-value\n"
253 )
254
255 cf = self.fromstring(config_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000256 output = StringIO.StringIO()
257 cf.write(output)
Fred Drakecc43b562010-02-19 05:24:30 +0000258 expect_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000259 "[DEFAULT]\n"
260 "foo = another very\n"
261 "\tlong line\n"
262 "\n"
263 "[Long Line]\n"
264 "foo = this line is much, much longer than my editor\n"
265 "\tlikes it.\n"
266 "\n"
267 )
Fred Drakecc43b562010-02-19 05:24:30 +0000268 if self.allow_no_value:
269 expect_string += (
270 "[Valueless]\n"
271 "option-without-value\n"
272 "\n"
273 )
274 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000275
Fred Drakeabc086f2004-05-18 03:29:52 +0000276 def test_set_string_types(self):
277 cf = self.fromstring("[sect]\n"
278 "option1=foo\n")
279 # Check that we don't get an exception when setting values in
280 # an existing section using strings:
281 class mystr(str):
282 pass
283 cf.set("sect", "option1", "splat")
284 cf.set("sect", "option1", mystr("splat"))
285 cf.set("sect", "option2", "splat")
286 cf.set("sect", "option2", mystr("splat"))
Zachary Ware1f702212013-12-10 14:09:20 -0600287
288 def test_set_unicode(self):
Fred Drakeabc086f2004-05-18 03:29:52 +0000289 try:
290 unicode
291 except NameError:
Zachary Ware1f702212013-12-10 14:09:20 -0600292 self.skipTest('no unicode support')
293
294 cf = self.fromstring("[sect]\n"
295 "option1=foo\n")
296 cf.set("sect", "option1", unicode("splat"))
297 cf.set("sect", "option2", unicode("splat"))
Fred Drakeabc086f2004-05-18 03:29:52 +0000298
Fred Drake82903142004-05-18 04:24:02 +0000299 def test_read_returns_file_list(self):
300 file1 = test_support.findfile("cfgparser.1")
301 # check when we pass a mix of readable and non-readable files:
302 cf = self.newconfig()
Mark Dickinson3e4caeb2009-02-21 20:27:01 +0000303 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000304 self.assertEqual(parsed_files, [file1])
305 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
306 # check when we pass only a filename:
307 cf = self.newconfig()
308 parsed_files = cf.read(file1)
309 self.assertEqual(parsed_files, [file1])
310 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
311 # check when we pass only missing files:
312 cf = self.newconfig()
Mark Dickinson3e4caeb2009-02-21 20:27:01 +0000313 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000314 self.assertEqual(parsed_files, [])
315 # check when we pass no files:
316 cf = self.newconfig()
317 parsed_files = cf.read([])
318 self.assertEqual(parsed_files, [])
319
Fred Drakec6f28912002-10-25 19:40:49 +0000320 # shared by subclasses
321 def get_interpolation_config(self):
322 return self.fromstring(
323 "[Foo]\n"
324 "bar=something %(with1)s interpolation (1 step)\n"
325 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
326 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
327 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
328 "with11=%(with10)s\n"
329 "with10=%(with9)s\n"
330 "with9=%(with8)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000331 "with8=%(With7)s\n"
332 "with7=%(WITH6)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000333 "with6=%(with5)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000334 "With5=%(with4)s\n"
335 "WITH4=%(with3)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000336 "with3=%(with2)s\n"
337 "with2=%(with1)s\n"
338 "with1=with\n"
339 "\n"
340 "[Mutual Recursion]\n"
341 "foo=%(bar)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000342 "bar=%(foo)s\n"
343 "\n"
344 "[Interpolation Error]\n"
345 "name=%(reference)s\n",
346 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000347 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000348
Fred Drake98e3b292002-10-25 20:42:44 +0000349 def check_items_config(self, expected):
350 cf = self.fromstring(
351 "[section]\n"
352 "name = value\n"
353 "key: |%(name)s| \n"
354 "getdefault: |%(default)s|\n"
355 "getname: |%(__name__)s|",
356 defaults={"default": "<default>"})
357 L = list(cf.items("section"))
358 L.sort()
359 self.assertEqual(L, expected)
360
Fred Drake8ef67672000-09-27 22:45:25 +0000361
Fred Drakec6f28912002-10-25 19:40:49 +0000362class ConfigParserTestCase(TestCaseBase):
Georg Brandl392c6fc2008-05-25 07:25:25 +0000363 config_class = ConfigParser.ConfigParser
Fred Drake0a1fa0e2010-08-10 13:09:54 +0000364 allow_no_value = True
Fred Drakec6f28912002-10-25 19:40:49 +0000365
366 def test_interpolation(self):
Brian Curtine4334b42010-07-26 02:30:15 +0000367 rawval = {
368 ConfigParser.ConfigParser: ("something %(with11)s "
369 "lots of interpolation (11 steps)"),
370 ConfigParser.SafeConfigParser: "%(with1)s",
371 }
Fred Drakec6f28912002-10-25 19:40:49 +0000372 cf = self.get_interpolation_config()
373 eq = self.assertEqual
374 eq(cf.get("Foo", "getname"), "Foo")
375 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
376 eq(cf.get("Foo", "bar9"),
377 "something with lots of interpolation (9 steps)")
378 eq(cf.get("Foo", "bar10"),
379 "something with lots of interpolation (10 steps)")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000380 self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")
Fred Drake95b96d32001-02-12 17:23:20 +0000381
Fred Drake54782192002-12-31 06:57:25 +0000382 def test_interpolation_missing_value(self):
Fred Drakecc43b562010-02-19 05:24:30 +0000383 self.get_interpolation_config()
Georg Brandl392c6fc2008-05-25 07:25:25 +0000384 e = self.get_error(ConfigParser.InterpolationError,
Fred Drake54782192002-12-31 06:57:25 +0000385 "Interpolation Error", "name")
386 self.assertEqual(e.reference, "reference")
387 self.assertEqual(e.section, "Interpolation Error")
388 self.assertEqual(e.option, "name")
389
Fred Drake98e3b292002-10-25 20:42:44 +0000390 def test_items(self):
391 self.check_items_config([('default', '<default>'),
392 ('getdefault', '|<default>|'),
393 ('getname', '|section|'),
394 ('key', '|value|'),
395 ('name', 'value')])
396
David Goodger1cbf2062004-10-03 15:55:09 +0000397 def test_set_nonstring_types(self):
398 cf = self.newconfig()
399 cf.add_section('non-string')
400 cf.set('non-string', 'int', 1)
401 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
402 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
403 '%(list)': '%(list)'})
404 cf.set('non-string', 'string_with_interpolation', '%(list)s')
Fred Drake0a1fa0e2010-08-10 13:09:54 +0000405 cf.set('non-string', 'no-value')
David Goodger1cbf2062004-10-03 15:55:09 +0000406 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
407 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
408 self.assertEqual(cf.get('non-string', 'list', raw=True),
409 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
410 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
411 self.assertEqual(cf.get('non-string', 'dict', raw=True),
412 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
413 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
414 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
415 raw=True), '%(list)s')
416 self.assertRaises(ValueError, cf.get, 'non-string',
417 'string_with_interpolation', raw=False)
Fred Drake0a1fa0e2010-08-10 13:09:54 +0000418 self.assertEqual(cf.get('non-string', 'no-value'), None)
David Goodger1cbf2062004-10-03 15:55:09 +0000419
Brian Curtine4334b42010-07-26 02:30:15 +0000420class MultilineValuesTestCase(TestCaseBase):
421 config_class = ConfigParser.ConfigParser
422 wonderful_spam = ("I'm having spam spam spam spam "
423 "spam spam spam beaked beans spam "
424 "spam spam and spam!").replace(' ', '\t\n')
425
426 def setUp(self):
427 cf = self.newconfig()
428 for i in range(100):
429 s = 'section{}'.format(i)
430 cf.add_section(s)
431 for j in range(10):
432 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
433 with open(test_support.TESTFN, 'w') as f:
434 cf.write(f)
435
436 def tearDown(self):
437 os.unlink(test_support.TESTFN)
438
439 def test_dominating_multiline_values(self):
440 # we're reading from file because this is where the code changed
441 # during performance updates in Python 3.2
442 cf_from_file = self.newconfig()
443 with open(test_support.TESTFN) as f:
444 cf_from_file.readfp(f)
445 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
446 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000447
Fred Drakec6f28912002-10-25 19:40:49 +0000448class RawConfigParserTestCase(TestCaseBase):
Georg Brandl392c6fc2008-05-25 07:25:25 +0000449 config_class = ConfigParser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000450
451 def test_interpolation(self):
452 cf = self.get_interpolation_config()
453 eq = self.assertEqual
454 eq(cf.get("Foo", "getname"), "%(__name__)s")
455 eq(cf.get("Foo", "bar"),
456 "something %(with1)s interpolation (1 step)")
457 eq(cf.get("Foo", "bar9"),
458 "something %(with9)s lots of interpolation (9 steps)")
459 eq(cf.get("Foo", "bar10"),
460 "something %(with10)s lots of interpolation (10 steps)")
461 eq(cf.get("Foo", "bar11"),
462 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000463
Fred Drake98e3b292002-10-25 20:42:44 +0000464 def test_items(self):
465 self.check_items_config([('default', '<default>'),
466 ('getdefault', '|%(default)s|'),
467 ('getname', '|%(__name__)s|'),
468 ('key', '|%(name)s|'),
469 ('name', 'value')])
470
David Goodger1cbf2062004-10-03 15:55:09 +0000471 def test_set_nonstring_types(self):
472 cf = self.newconfig()
473 cf.add_section('non-string')
474 cf.set('non-string', 'int', 1)
475 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
476 cf.set('non-string', 'dict', {'pi': 3.14159})
477 self.assertEqual(cf.get('non-string', 'int'), 1)
478 self.assertEqual(cf.get('non-string', 'list'),
479 [0, 1, 1, 2, 3, 5, 8, 13])
480 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000481
Fred Drake8ef67672000-09-27 22:45:25 +0000482
Fred Drake0eebd5c2002-10-25 21:52:00 +0000483class SafeConfigParserTestCase(ConfigParserTestCase):
Georg Brandl392c6fc2008-05-25 07:25:25 +0000484 config_class = ConfigParser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000485
486 def test_safe_interpolation(self):
487 # See http://www.python.org/sf/511737
488 cf = self.fromstring("[section]\n"
489 "option1=xxx\n"
490 "option2=%(option1)s/xxx\n"
491 "ok=%(option1)s/%%s\n"
492 "not_ok=%(option2)s/%%s")
493 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
494 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
495
Georg Brandl92a6bae2007-03-13 17:43:32 +0000496 def test_set_malformatted_interpolation(self):
497 cf = self.fromstring("[sect]\n"
498 "option1=foo\n")
499
500 self.assertEqual(cf.get('sect', "option1"), "foo")
501
502 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
503 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
504 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
505
506 self.assertEqual(cf.get('sect', "option1"), "foo")
507
Georg Brandl21cf5ee2009-04-12 17:24:11 +0000508 # bug #5741: double percents are *not* malformed
509 cf.set("sect", "option2", "foo%%bar")
510 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
511
David Goodger1cbf2062004-10-03 15:55:09 +0000512 def test_set_nonstring_types(self):
513 cf = self.fromstring("[sect]\n"
514 "option1=foo\n")
515 # Check that we get a TypeError when setting non-string values
516 # in an existing section:
517 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
518 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
519 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
520 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
521 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
522 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
523
Facundo Batistab12f0b52008-02-23 12:46:10 +0000524 def test_add_section_default_1(self):
525 cf = self.newconfig()
526 self.assertRaises(ValueError, cf.add_section, "default")
527
528 def test_add_section_default_2(self):
529 cf = self.newconfig()
530 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
531
Fred Drakecc43b562010-02-19 05:24:30 +0000532
533class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
534 allow_no_value = True
535
Raymond Hettinger3ea52242011-08-09 12:07:15 -0700536class TestChainMap(unittest.TestCase):
537 def test_issue_12717(self):
538 d1 = dict(red=1, green=2)
539 d2 = dict(green=3, blue=4)
540 dcomb = d2.copy()
541 dcomb.update(d1)
542 cm = ConfigParser._Chainmap(d1, d2)
543 self.assertIsInstance(cm.keys(), list)
544 self.assertEqual(set(cm.keys()), set(dcomb.keys())) # keys()
545 self.assertEqual(set(cm.values()), set(dcomb.values())) # values()
546 self.assertEqual(set(cm.items()), set(dcomb.items())) # items()
547 self.assertEqual(set(cm), set(dcomb)) # __iter__ ()
548 self.assertEqual(cm, dcomb) # __eq__()
549 self.assertEqual([cm[k] for k in dcomb], dcomb.values()) # __getitem__()
550 klist = 'red green blue black brown'.split()
551 self.assertEqual([cm.get(k, 10) for k in klist],
552 [dcomb.get(k, 10) for k in klist]) # get()
553 self.assertEqual([k in cm for k in klist],
554 [k in dcomb for k in klist]) # __contains__()
Ezio Melotti030aa352011-11-06 18:50:32 +0200555 with test_support.check_py3k_warnings():
556 self.assertEqual([cm.has_key(k) for k in klist],
557 [dcomb.has_key(k) for k in klist]) # has_key()
Fred Drakecc43b562010-02-19 05:24:30 +0000558
Fred Drakea1e627d2010-09-03 03:55:50 +0000559class Issue7005TestCase(unittest.TestCase):
560 """Test output when None is set() as a value and allow_no_value == False.
561
562 http://bugs.python.org/issue7005
563
564 """
565
566 expected_output = "[section]\noption = None\n\n"
567
568 def prepare(self, config_class):
569 # This is the default, but that's the point.
570 cp = config_class(allow_no_value=False)
571 cp.add_section("section")
572 cp.set("section", "option", None)
573 sio = StringIO.StringIO()
574 cp.write(sio)
575 return sio.getvalue()
576
577 def test_none_as_value_stringified(self):
578 output = self.prepare(ConfigParser.ConfigParser)
579 self.assertEqual(output, self.expected_output)
580
581 def test_none_as_value_stringified_raw(self):
582 output = self.prepare(ConfigParser.RawConfigParser)
583 self.assertEqual(output, self.expected_output)
584
585
Martin v. Löwisa00bcac2006-12-03 12:01:53 +0000586class SortedTestCase(RawConfigParserTestCase):
587 def newconfig(self, defaults=None):
588 self.cf = self.config_class(defaults=defaults, dict_type=SortedDict)
589 return self.cf
590
591 def test_sorted(self):
592 self.fromstring("[b]\n"
593 "o4=1\n"
594 "o3=2\n"
595 "o2=3\n"
596 "o1=4\n"
597 "[a]\n"
Tim Petersf733abb2007-01-30 03:03:46 +0000598 "k=v\n")
Martin v. Löwisa00bcac2006-12-03 12:01:53 +0000599 output = StringIO.StringIO()
600 self.cf.write(output)
Ezio Melotti2623a372010-11-21 13:34:58 +0000601 self.assertEqual(output.getvalue(),
602 "[a]\n"
603 "k = v\n\n"
604 "[b]\n"
605 "o1 = 4\n"
606 "o2 = 3\n"
607 "o3 = 2\n"
608 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000609
Fred Drakecc43b562010-02-19 05:24:30 +0000610
Łukasz Langa631c2582012-01-20 17:02:08 +0100611class ExceptionPicklingTestCase(unittest.TestCase):
612 """Tests for issue #13760: ConfigParser exceptions are not picklable."""
613
614 def test_error(self):
615 import pickle
616 e1 = ConfigParser.Error('value')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200617 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
618 pickled = pickle.dumps(e1, proto)
619 e2 = pickle.loads(pickled)
620 self.assertEqual(e1.message, e2.message)
621 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100622
623 def test_nosectionerror(self):
624 import pickle
625 e1 = ConfigParser.NoSectionError('section')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200626 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
627 pickled = pickle.dumps(e1, proto)
628 e2 = pickle.loads(pickled)
629 self.assertEqual(e1.message, e2.message)
630 self.assertEqual(e1.args, e2.args)
631 self.assertEqual(e1.section, e2.section)
632 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100633
634 def test_nooptionerror(self):
635 import pickle
636 e1 = ConfigParser.NoOptionError('option', 'section')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200637 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
638 pickled = pickle.dumps(e1, proto)
639 e2 = pickle.loads(pickled)
640 self.assertEqual(e1.message, e2.message)
641 self.assertEqual(e1.args, e2.args)
642 self.assertEqual(e1.section, e2.section)
643 self.assertEqual(e1.option, e2.option)
644 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100645
646 def test_duplicatesectionerror(self):
647 import pickle
648 e1 = ConfigParser.DuplicateSectionError('section')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200649 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
650 pickled = pickle.dumps(e1, proto)
651 e2 = pickle.loads(pickled)
652 self.assertEqual(e1.message, e2.message)
653 self.assertEqual(e1.args, e2.args)
654 self.assertEqual(e1.section, e2.section)
655 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100656
657 def test_interpolationerror(self):
658 import pickle
659 e1 = ConfigParser.InterpolationError('option', 'section', 'msg')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200660 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
661 pickled = pickle.dumps(e1, proto)
662 e2 = pickle.loads(pickled)
663 self.assertEqual(e1.message, e2.message)
664 self.assertEqual(e1.args, e2.args)
665 self.assertEqual(e1.section, e2.section)
666 self.assertEqual(e1.option, e2.option)
667 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100668
669 def test_interpolationmissingoptionerror(self):
670 import pickle
671 e1 = ConfigParser.InterpolationMissingOptionError('option', 'section',
672 'rawval', 'reference')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200673 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
674 pickled = pickle.dumps(e1, proto)
675 e2 = pickle.loads(pickled)
676 self.assertEqual(e1.message, e2.message)
677 self.assertEqual(e1.args, e2.args)
678 self.assertEqual(e1.section, e2.section)
679 self.assertEqual(e1.option, e2.option)
680 self.assertEqual(e1.reference, e2.reference)
681 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100682
683 def test_interpolationsyntaxerror(self):
684 import pickle
685 e1 = ConfigParser.InterpolationSyntaxError('option', 'section', 'msg')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200686 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
687 pickled = pickle.dumps(e1, proto)
688 e2 = pickle.loads(pickled)
689 self.assertEqual(e1.message, e2.message)
690 self.assertEqual(e1.args, e2.args)
691 self.assertEqual(e1.section, e2.section)
692 self.assertEqual(e1.option, e2.option)
693 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100694
695 def test_interpolationdeptherror(self):
696 import pickle
697 e1 = ConfigParser.InterpolationDepthError('option', 'section',
698 'rawval')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200699 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
700 pickled = pickle.dumps(e1, proto)
701 e2 = pickle.loads(pickled)
702 self.assertEqual(e1.message, e2.message)
703 self.assertEqual(e1.args, e2.args)
704 self.assertEqual(e1.section, e2.section)
705 self.assertEqual(e1.option, e2.option)
706 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100707
708 def test_parsingerror(self):
709 import pickle
710 e1 = ConfigParser.ParsingError('source')
711 e1.append(1, 'line1')
712 e1.append(2, 'line2')
713 e1.append(3, 'line3')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200714 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
715 pickled = pickle.dumps(e1, proto)
716 e2 = pickle.loads(pickled)
717 self.assertEqual(e1.message, e2.message)
718 self.assertEqual(e1.args, e2.args)
719 self.assertEqual(e1.filename, e2.filename)
720 self.assertEqual(e1.errors, e2.errors)
721 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100722
723 def test_missingsectionheadererror(self):
724 import pickle
725 e1 = ConfigParser.MissingSectionHeaderError('filename', 123, 'line')
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200726 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
727 pickled = pickle.dumps(e1, proto)
728 e2 = pickle.loads(pickled)
729 self.assertEqual(e1.message, e2.message)
730 self.assertEqual(e1.args, e2.args)
731 self.assertEqual(e1.line, e2.line)
732 self.assertEqual(e1.filename, e2.filename)
733 self.assertEqual(e1.lineno, e2.lineno)
734 self.assertEqual(repr(e1), repr(e2))
Łukasz Langa631c2582012-01-20 17:02:08 +0100735
736
Fred Drakec6f28912002-10-25 19:40:49 +0000737def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000738 test_support.run_unittest(
739 ConfigParserTestCase,
Brian Curtine4334b42010-07-26 02:30:15 +0000740 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000741 RawConfigParserTestCase,
Martin v. Löwisa00bcac2006-12-03 12:01:53 +0000742 SafeConfigParserTestCase,
Fred Drakecc43b562010-02-19 05:24:30 +0000743 SafeConfigParserTestCaseNoValue,
Brian Curtine4334b42010-07-26 02:30:15 +0000744 SortedTestCase,
Fred Drakea1e627d2010-09-03 03:55:50 +0000745 Issue7005TestCase,
Raymond Hettinger3ea52242011-08-09 12:07:15 -0700746 TestChainMap,
Łukasz Langa631c2582012-01-20 17:02:08 +0100747 ExceptionPicklingTestCase,
Fred Drakecc43b562010-02-19 05:24:30 +0000748 )
749
Fred Drake3af0eb82002-10-25 18:09:24 +0000750
Fred Drakec6f28912002-10-25 19:40:49 +0000751if __name__ == "__main__":
752 test_main()