blob: f0073f04af762b02744b3b50811c2d57d9bf377e [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"))
287 try:
288 unicode
289 except NameError:
290 pass
291 else:
292 cf.set("sect", "option1", unicode("splat"))
293 cf.set("sect", "option2", unicode("splat"))
294
Fred Drake82903142004-05-18 04:24:02 +0000295 def test_read_returns_file_list(self):
296 file1 = test_support.findfile("cfgparser.1")
297 # check when we pass a mix of readable and non-readable files:
298 cf = self.newconfig()
Mark Dickinson3e4caeb2009-02-21 20:27:01 +0000299 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000300 self.assertEqual(parsed_files, [file1])
301 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
302 # check when we pass only a filename:
303 cf = self.newconfig()
304 parsed_files = cf.read(file1)
305 self.assertEqual(parsed_files, [file1])
306 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
307 # check when we pass only missing files:
308 cf = self.newconfig()
Mark Dickinson3e4caeb2009-02-21 20:27:01 +0000309 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000310 self.assertEqual(parsed_files, [])
311 # check when we pass no files:
312 cf = self.newconfig()
313 parsed_files = cf.read([])
314 self.assertEqual(parsed_files, [])
315
Fred Drakec6f28912002-10-25 19:40:49 +0000316 # shared by subclasses
317 def get_interpolation_config(self):
318 return self.fromstring(
319 "[Foo]\n"
320 "bar=something %(with1)s interpolation (1 step)\n"
321 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
322 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
323 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
324 "with11=%(with10)s\n"
325 "with10=%(with9)s\n"
326 "with9=%(with8)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000327 "with8=%(With7)s\n"
328 "with7=%(WITH6)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000329 "with6=%(with5)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000330 "With5=%(with4)s\n"
331 "WITH4=%(with3)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000332 "with3=%(with2)s\n"
333 "with2=%(with1)s\n"
334 "with1=with\n"
335 "\n"
336 "[Mutual Recursion]\n"
337 "foo=%(bar)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000338 "bar=%(foo)s\n"
339 "\n"
340 "[Interpolation Error]\n"
341 "name=%(reference)s\n",
342 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000343 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000344
Fred Drake98e3b292002-10-25 20:42:44 +0000345 def check_items_config(self, expected):
346 cf = self.fromstring(
347 "[section]\n"
348 "name = value\n"
349 "key: |%(name)s| \n"
350 "getdefault: |%(default)s|\n"
351 "getname: |%(__name__)s|",
352 defaults={"default": "<default>"})
353 L = list(cf.items("section"))
354 L.sort()
355 self.assertEqual(L, expected)
356
Fred Drake8ef67672000-09-27 22:45:25 +0000357
Fred Drakec6f28912002-10-25 19:40:49 +0000358class ConfigParserTestCase(TestCaseBase):
Georg Brandl392c6fc2008-05-25 07:25:25 +0000359 config_class = ConfigParser.ConfigParser
Fred Drake0a1fa0e2010-08-10 13:09:54 +0000360 allow_no_value = True
Fred Drakec6f28912002-10-25 19:40:49 +0000361
362 def test_interpolation(self):
Brian Curtine4334b42010-07-26 02:30:15 +0000363 rawval = {
364 ConfigParser.ConfigParser: ("something %(with11)s "
365 "lots of interpolation (11 steps)"),
366 ConfigParser.SafeConfigParser: "%(with1)s",
367 }
Fred Drakec6f28912002-10-25 19:40:49 +0000368 cf = self.get_interpolation_config()
369 eq = self.assertEqual
370 eq(cf.get("Foo", "getname"), "Foo")
371 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
372 eq(cf.get("Foo", "bar9"),
373 "something with lots of interpolation (9 steps)")
374 eq(cf.get("Foo", "bar10"),
375 "something with lots of interpolation (10 steps)")
Georg Brandl392c6fc2008-05-25 07:25:25 +0000376 self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")
Fred Drake95b96d32001-02-12 17:23:20 +0000377
Fred Drake54782192002-12-31 06:57:25 +0000378 def test_interpolation_missing_value(self):
Fred Drakecc43b562010-02-19 05:24:30 +0000379 self.get_interpolation_config()
Georg Brandl392c6fc2008-05-25 07:25:25 +0000380 e = self.get_error(ConfigParser.InterpolationError,
Fred Drake54782192002-12-31 06:57:25 +0000381 "Interpolation Error", "name")
382 self.assertEqual(e.reference, "reference")
383 self.assertEqual(e.section, "Interpolation Error")
384 self.assertEqual(e.option, "name")
385
Fred Drake98e3b292002-10-25 20:42:44 +0000386 def test_items(self):
387 self.check_items_config([('default', '<default>'),
388 ('getdefault', '|<default>|'),
389 ('getname', '|section|'),
390 ('key', '|value|'),
391 ('name', 'value')])
392
David Goodger1cbf2062004-10-03 15:55:09 +0000393 def test_set_nonstring_types(self):
394 cf = self.newconfig()
395 cf.add_section('non-string')
396 cf.set('non-string', 'int', 1)
397 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
398 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
399 '%(list)': '%(list)'})
400 cf.set('non-string', 'string_with_interpolation', '%(list)s')
Fred Drake0a1fa0e2010-08-10 13:09:54 +0000401 cf.set('non-string', 'no-value')
David Goodger1cbf2062004-10-03 15:55:09 +0000402 self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
403 self.assertRaises(TypeError, cf.get, 'non-string', 'int')
404 self.assertEqual(cf.get('non-string', 'list', raw=True),
405 [0, 1, 1, 2, 3, 5, 8, 13, '%('])
406 self.assertRaises(TypeError, cf.get, 'non-string', 'list')
407 self.assertEqual(cf.get('non-string', 'dict', raw=True),
408 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
409 self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
410 self.assertEqual(cf.get('non-string', 'string_with_interpolation',
411 raw=True), '%(list)s')
412 self.assertRaises(ValueError, cf.get, 'non-string',
413 'string_with_interpolation', raw=False)
Fred Drake0a1fa0e2010-08-10 13:09:54 +0000414 self.assertEqual(cf.get('non-string', 'no-value'), None)
David Goodger1cbf2062004-10-03 15:55:09 +0000415
Brian Curtine4334b42010-07-26 02:30:15 +0000416class MultilineValuesTestCase(TestCaseBase):
417 config_class = ConfigParser.ConfigParser
418 wonderful_spam = ("I'm having spam spam spam spam "
419 "spam spam spam beaked beans spam "
420 "spam spam and spam!").replace(' ', '\t\n')
421
422 def setUp(self):
423 cf = self.newconfig()
424 for i in range(100):
425 s = 'section{}'.format(i)
426 cf.add_section(s)
427 for j in range(10):
428 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
429 with open(test_support.TESTFN, 'w') as f:
430 cf.write(f)
431
432 def tearDown(self):
433 os.unlink(test_support.TESTFN)
434
435 def test_dominating_multiline_values(self):
436 # we're reading from file because this is where the code changed
437 # during performance updates in Python 3.2
438 cf_from_file = self.newconfig()
439 with open(test_support.TESTFN) as f:
440 cf_from_file.readfp(f)
441 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
442 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000443
Fred Drakec6f28912002-10-25 19:40:49 +0000444class RawConfigParserTestCase(TestCaseBase):
Georg Brandl392c6fc2008-05-25 07:25:25 +0000445 config_class = ConfigParser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000446
447 def test_interpolation(self):
448 cf = self.get_interpolation_config()
449 eq = self.assertEqual
450 eq(cf.get("Foo", "getname"), "%(__name__)s")
451 eq(cf.get("Foo", "bar"),
452 "something %(with1)s interpolation (1 step)")
453 eq(cf.get("Foo", "bar9"),
454 "something %(with9)s lots of interpolation (9 steps)")
455 eq(cf.get("Foo", "bar10"),
456 "something %(with10)s lots of interpolation (10 steps)")
457 eq(cf.get("Foo", "bar11"),
458 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000459
Fred Drake98e3b292002-10-25 20:42:44 +0000460 def test_items(self):
461 self.check_items_config([('default', '<default>'),
462 ('getdefault', '|%(default)s|'),
463 ('getname', '|%(__name__)s|'),
464 ('key', '|%(name)s|'),
465 ('name', 'value')])
466
David Goodger1cbf2062004-10-03 15:55:09 +0000467 def test_set_nonstring_types(self):
468 cf = self.newconfig()
469 cf.add_section('non-string')
470 cf.set('non-string', 'int', 1)
471 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
472 cf.set('non-string', 'dict', {'pi': 3.14159})
473 self.assertEqual(cf.get('non-string', 'int'), 1)
474 self.assertEqual(cf.get('non-string', 'list'),
475 [0, 1, 1, 2, 3, 5, 8, 13])
476 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Tim Petersab9b32c2004-10-03 18:35:19 +0000477
Fred Drake8ef67672000-09-27 22:45:25 +0000478
Fred Drake0eebd5c2002-10-25 21:52:00 +0000479class SafeConfigParserTestCase(ConfigParserTestCase):
Georg Brandl392c6fc2008-05-25 07:25:25 +0000480 config_class = ConfigParser.SafeConfigParser
Fred Drake0eebd5c2002-10-25 21:52:00 +0000481
482 def test_safe_interpolation(self):
483 # See http://www.python.org/sf/511737
484 cf = self.fromstring("[section]\n"
485 "option1=xxx\n"
486 "option2=%(option1)s/xxx\n"
487 "ok=%(option1)s/%%s\n"
488 "not_ok=%(option2)s/%%s")
489 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
490 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
491
Georg Brandl92a6bae2007-03-13 17:43:32 +0000492 def test_set_malformatted_interpolation(self):
493 cf = self.fromstring("[sect]\n"
494 "option1=foo\n")
495
496 self.assertEqual(cf.get('sect', "option1"), "foo")
497
498 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
499 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
500 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
501
502 self.assertEqual(cf.get('sect', "option1"), "foo")
503
Georg Brandl21cf5ee2009-04-12 17:24:11 +0000504 # bug #5741: double percents are *not* malformed
505 cf.set("sect", "option2", "foo%%bar")
506 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
507
David Goodger1cbf2062004-10-03 15:55:09 +0000508 def test_set_nonstring_types(self):
509 cf = self.fromstring("[sect]\n"
510 "option1=foo\n")
511 # Check that we get a TypeError when setting non-string values
512 # in an existing section:
513 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
514 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
515 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
516 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
517 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
518 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
519
Facundo Batistab12f0b52008-02-23 12:46:10 +0000520 def test_add_section_default_1(self):
521 cf = self.newconfig()
522 self.assertRaises(ValueError, cf.add_section, "default")
523
524 def test_add_section_default_2(self):
525 cf = self.newconfig()
526 self.assertRaises(ValueError, cf.add_section, "DEFAULT")
527
Fred Drakecc43b562010-02-19 05:24:30 +0000528
529class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
530 allow_no_value = True
531
Raymond Hettinger3ea52242011-08-09 12:07:15 -0700532class TestChainMap(unittest.TestCase):
533 def test_issue_12717(self):
534 d1 = dict(red=1, green=2)
535 d2 = dict(green=3, blue=4)
536 dcomb = d2.copy()
537 dcomb.update(d1)
538 cm = ConfigParser._Chainmap(d1, d2)
539 self.assertIsInstance(cm.keys(), list)
540 self.assertEqual(set(cm.keys()), set(dcomb.keys())) # keys()
541 self.assertEqual(set(cm.values()), set(dcomb.values())) # values()
542 self.assertEqual(set(cm.items()), set(dcomb.items())) # items()
543 self.assertEqual(set(cm), set(dcomb)) # __iter__ ()
544 self.assertEqual(cm, dcomb) # __eq__()
545 self.assertEqual([cm[k] for k in dcomb], dcomb.values()) # __getitem__()
546 klist = 'red green blue black brown'.split()
547 self.assertEqual([cm.get(k, 10) for k in klist],
548 [dcomb.get(k, 10) for k in klist]) # get()
549 self.assertEqual([k in cm for k in klist],
550 [k in dcomb for k in klist]) # __contains__()
Ezio Melotti030aa352011-11-06 18:50:32 +0200551 with test_support.check_py3k_warnings():
552 self.assertEqual([cm.has_key(k) for k in klist],
553 [dcomb.has_key(k) for k in klist]) # has_key()
Fred Drakecc43b562010-02-19 05:24:30 +0000554
Fred Drakea1e627d2010-09-03 03:55:50 +0000555class Issue7005TestCase(unittest.TestCase):
556 """Test output when None is set() as a value and allow_no_value == False.
557
558 http://bugs.python.org/issue7005
559
560 """
561
562 expected_output = "[section]\noption = None\n\n"
563
564 def prepare(self, config_class):
565 # This is the default, but that's the point.
566 cp = config_class(allow_no_value=False)
567 cp.add_section("section")
568 cp.set("section", "option", None)
569 sio = StringIO.StringIO()
570 cp.write(sio)
571 return sio.getvalue()
572
573 def test_none_as_value_stringified(self):
574 output = self.prepare(ConfigParser.ConfigParser)
575 self.assertEqual(output, self.expected_output)
576
577 def test_none_as_value_stringified_raw(self):
578 output = self.prepare(ConfigParser.RawConfigParser)
579 self.assertEqual(output, self.expected_output)
580
581
Martin v. Löwisa00bcac2006-12-03 12:01:53 +0000582class SortedTestCase(RawConfigParserTestCase):
583 def newconfig(self, defaults=None):
584 self.cf = self.config_class(defaults=defaults, dict_type=SortedDict)
585 return self.cf
586
587 def test_sorted(self):
588 self.fromstring("[b]\n"
589 "o4=1\n"
590 "o3=2\n"
591 "o2=3\n"
592 "o1=4\n"
593 "[a]\n"
Tim Petersf733abb2007-01-30 03:03:46 +0000594 "k=v\n")
Martin v. Löwisa00bcac2006-12-03 12:01:53 +0000595 output = StringIO.StringIO()
596 self.cf.write(output)
Ezio Melotti2623a372010-11-21 13:34:58 +0000597 self.assertEqual(output.getvalue(),
598 "[a]\n"
599 "k = v\n\n"
600 "[b]\n"
601 "o1 = 4\n"
602 "o2 = 3\n"
603 "o3 = 2\n"
604 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +0000605
Fred Drakecc43b562010-02-19 05:24:30 +0000606
Łukasz Langa631c2582012-01-20 17:02:08 +0100607class ExceptionPicklingTestCase(unittest.TestCase):
608 """Tests for issue #13760: ConfigParser exceptions are not picklable."""
609
610 def test_error(self):
611 import pickle
612 e1 = ConfigParser.Error('value')
613 pickled = pickle.dumps(e1)
614 e2 = pickle.loads(pickled)
615 self.assertEqual(e1.message, e2.message)
616 self.assertEqual(repr(e1), repr(e2))
617
618 def test_nosectionerror(self):
619 import pickle
620 e1 = ConfigParser.NoSectionError('section')
621 pickled = pickle.dumps(e1)
622 e2 = pickle.loads(pickled)
623 self.assertEqual(e1.message, e2.message)
624 self.assertEqual(e1.args, e2.args)
625 self.assertEqual(e1.section, e2.section)
626 self.assertEqual(repr(e1), repr(e2))
627
628 def test_nooptionerror(self):
629 import pickle
630 e1 = ConfigParser.NoOptionError('option', 'section')
631 pickled = pickle.dumps(e1)
632 e2 = pickle.loads(pickled)
633 self.assertEqual(e1.message, e2.message)
634 self.assertEqual(e1.args, e2.args)
635 self.assertEqual(e1.section, e2.section)
636 self.assertEqual(e1.option, e2.option)
637 self.assertEqual(repr(e1), repr(e2))
638
639 def test_duplicatesectionerror(self):
640 import pickle
641 e1 = ConfigParser.DuplicateSectionError('section')
642 pickled = pickle.dumps(e1)
643 e2 = pickle.loads(pickled)
644 self.assertEqual(e1.message, e2.message)
645 self.assertEqual(e1.args, e2.args)
646 self.assertEqual(e1.section, e2.section)
647 self.assertEqual(repr(e1), repr(e2))
648
649 def test_interpolationerror(self):
650 import pickle
651 e1 = ConfigParser.InterpolationError('option', 'section', 'msg')
652 pickled = pickle.dumps(e1)
653 e2 = pickle.loads(pickled)
654 self.assertEqual(e1.message, e2.message)
655 self.assertEqual(e1.args, e2.args)
656 self.assertEqual(e1.section, e2.section)
657 self.assertEqual(e1.option, e2.option)
658 self.assertEqual(repr(e1), repr(e2))
659
660 def test_interpolationmissingoptionerror(self):
661 import pickle
662 e1 = ConfigParser.InterpolationMissingOptionError('option', 'section',
663 'rawval', 'reference')
664 pickled = pickle.dumps(e1)
665 e2 = pickle.loads(pickled)
666 self.assertEqual(e1.message, e2.message)
667 self.assertEqual(e1.args, e2.args)
668 self.assertEqual(e1.section, e2.section)
669 self.assertEqual(e1.option, e2.option)
670 self.assertEqual(e1.reference, e2.reference)
671 self.assertEqual(repr(e1), repr(e2))
672
673 def test_interpolationsyntaxerror(self):
674 import pickle
675 e1 = ConfigParser.InterpolationSyntaxError('option', 'section', 'msg')
676 pickled = pickle.dumps(e1)
677 e2 = pickle.loads(pickled)
678 self.assertEqual(e1.message, e2.message)
679 self.assertEqual(e1.args, e2.args)
680 self.assertEqual(e1.section, e2.section)
681 self.assertEqual(e1.option, e2.option)
682 self.assertEqual(repr(e1), repr(e2))
683
684 def test_interpolationdeptherror(self):
685 import pickle
686 e1 = ConfigParser.InterpolationDepthError('option', 'section',
687 'rawval')
688 pickled = pickle.dumps(e1)
689 e2 = pickle.loads(pickled)
690 self.assertEqual(e1.message, e2.message)
691 self.assertEqual(e1.args, e2.args)
692 self.assertEqual(e1.section, e2.section)
693 self.assertEqual(e1.option, e2.option)
694 self.assertEqual(repr(e1), repr(e2))
695
696 def test_parsingerror(self):
697 import pickle
698 e1 = ConfigParser.ParsingError('source')
699 e1.append(1, 'line1')
700 e1.append(2, 'line2')
701 e1.append(3, 'line3')
702 pickled = pickle.dumps(e1)
703 e2 = pickle.loads(pickled)
704 self.assertEqual(e1.message, e2.message)
705 self.assertEqual(e1.args, e2.args)
706 self.assertEqual(e1.filename, e2.filename)
707 self.assertEqual(e1.errors, e2.errors)
708 self.assertEqual(repr(e1), repr(e2))
709
710 def test_missingsectionheadererror(self):
711 import pickle
712 e1 = ConfigParser.MissingSectionHeaderError('filename', 123, 'line')
713 pickled = pickle.dumps(e1)
714 e2 = pickle.loads(pickled)
715 self.assertEqual(e1.message, e2.message)
716 self.assertEqual(e1.args, e2.args)
717 self.assertEqual(e1.line, e2.line)
718 self.assertEqual(e1.filename, e2.filename)
719 self.assertEqual(e1.lineno, e2.lineno)
720 self.assertEqual(repr(e1), repr(e2))
721
722
Fred Drakec6f28912002-10-25 19:40:49 +0000723def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000724 test_support.run_unittest(
725 ConfigParserTestCase,
Brian Curtine4334b42010-07-26 02:30:15 +0000726 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000727 RawConfigParserTestCase,
Martin v. Löwisa00bcac2006-12-03 12:01:53 +0000728 SafeConfigParserTestCase,
Fred Drakecc43b562010-02-19 05:24:30 +0000729 SafeConfigParserTestCaseNoValue,
Brian Curtine4334b42010-07-26 02:30:15 +0000730 SortedTestCase,
Fred Drakea1e627d2010-09-03 03:55:50 +0000731 Issue7005TestCase,
Raymond Hettinger3ea52242011-08-09 12:07:15 -0700732 TestChainMap,
Łukasz Langa631c2582012-01-20 17:02:08 +0100733 ExceptionPicklingTestCase,
Fred Drakecc43b562010-02-19 05:24:30 +0000734 )
735
Fred Drake3af0eb82002-10-25 18:09:24 +0000736
Fred Drakec6f28912002-10-25 19:40:49 +0000737if __name__ == "__main__":
738 test_main()