blob: f7d9a26e896e0654e95f907852dc9797a280d9ba [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
Łukasz Langa535c0772010-12-04 13:48:13 +00005import sys
Georg Brandl96a60ae2010-07-28 13:13:46 +00006import textwrap
Łukasz Langa535c0772010-12-04 13:48:13 +00007import unittest
Łukasz Langa71b37a52010-12-17 21:56:32 +00008import warnings
Fred Drake8ef67672000-09-27 22:45:25 +00009
Benjamin Petersonee8712c2008-05-20 21:35:26 +000010from test import support
Fred Drake3d5f7e82000-12-04 16:30:40 +000011
Raymond Hettingerf80680d2008-02-06 00:07:11 +000012class SortedDict(collections.UserDict):
Fred Drake03c44a32010-02-19 06:08:41 +000013
Thomas Wouters89f507f2006-12-13 04:49:30 +000014 def items(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000015 return sorted(self.data.items())
Thomas Wouters89f507f2006-12-13 04:49:30 +000016
17 def keys(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000018 return sorted(self.data.keys())
Thomas Wouters9fe394c2007-02-05 01:24:16 +000019
Thomas Wouters89f507f2006-12-13 04:49:30 +000020 def values(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000021 return [i[1] for i in self.items()]
Thomas Wouters89f507f2006-12-13 04:49:30 +000022
23 def iteritems(self): return iter(self.items())
24 def iterkeys(self): return iter(self.keys())
25 __iter__ = iterkeys
26 def itervalues(self): return iter(self.values())
Fred Drake3d5f7e82000-12-04 16:30:40 +000027
Fred Drake03c44a32010-02-19 06:08:41 +000028
Georg Brandl96a60ae2010-07-28 13:13:46 +000029class CfgParserTestCaseClass(unittest.TestCase):
Fred Drake03c44a32010-02-19 06:08:41 +000030 allow_no_value = False
Georg Brandl96a60ae2010-07-28 13:13:46 +000031 delimiters = ('=', ':')
32 comment_prefixes = (';', '#')
Łukasz Langab25a7912010-12-17 01:32:29 +000033 inline_comment_prefixes = (';', '#')
Georg Brandl96a60ae2010-07-28 13:13:46 +000034 empty_lines_in_values = True
35 dict_type = configparser._default_dict
Fred Drakea4923622010-08-09 12:52:45 +000036 strict = False
Łukasz Langac264c092010-11-20 16:15:37 +000037 default_section = configparser.DEFAULTSECT
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000038 interpolation = configparser._UNSET
Fred Drake03c44a32010-02-19 06:08:41 +000039
Fred Drakec6f28912002-10-25 19:40:49 +000040 def newconfig(self, defaults=None):
Georg Brandl96a60ae2010-07-28 13:13:46 +000041 arguments = dict(
Fred Drakea4923622010-08-09 12:52:45 +000042 defaults=defaults,
Georg Brandl96a60ae2010-07-28 13:13:46 +000043 allow_no_value=self.allow_no_value,
44 delimiters=self.delimiters,
45 comment_prefixes=self.comment_prefixes,
Łukasz Langab25a7912010-12-17 01:32:29 +000046 inline_comment_prefixes=self.inline_comment_prefixes,
Georg Brandl96a60ae2010-07-28 13:13:46 +000047 empty_lines_in_values=self.empty_lines_in_values,
48 dict_type=self.dict_type,
Fred Drakea4923622010-08-09 12:52:45 +000049 strict=self.strict,
Łukasz Langac264c092010-11-20 16:15:37 +000050 default_section=self.default_section,
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000051 interpolation=self.interpolation,
Georg Brandl96a60ae2010-07-28 13:13:46 +000052 )
Łukasz Langa7f64c8a2010-12-16 01:16:22 +000053 instance = self.config_class(**arguments)
Łukasz Langab6a6f5f2010-12-03 16:28:00 +000054 return instance
Fred Drake8ef67672000-09-27 22:45:25 +000055
Fred Drakec6f28912002-10-25 19:40:49 +000056 def fromstring(self, string, defaults=None):
57 cf = self.newconfig(defaults)
Fred Drakea4923622010-08-09 12:52:45 +000058 cf.read_string(string)
Fred Drakec6f28912002-10-25 19:40:49 +000059 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000060
Georg Brandl96a60ae2010-07-28 13:13:46 +000061class BasicTestCase(CfgParserTestCaseClass):
62
Fred Drakea4923622010-08-09 12:52:45 +000063 def basic_test(self, cf):
Georg Brandl96a60ae2010-07-28 13:13:46 +000064 E = ['Commented Bar',
65 'Foo Bar',
66 'Internationalized Stuff',
67 'Long Line',
68 'Section\\with$weird%characters[\t',
69 'Spaces',
70 'Spacey Bar',
71 'Spacey Bar From The Beginning',
Fred Drakecc645b92010-09-04 04:35:34 +000072 'Types',
Fred Drake03c44a32010-02-19 06:08:41 +000073 ]
Łukasz Langa26d513c2010-11-10 18:57:39 +000074
Fred Drake03c44a32010-02-19 06:08:41 +000075 if self.allow_no_value:
Fred Drakecc645b92010-09-04 04:35:34 +000076 E.append('NoValue')
Fred Drake03c44a32010-02-19 06:08:41 +000077 E.sort()
Łukasz Langa71b37a52010-12-17 21:56:32 +000078 F = [('baz', 'qwe'), ('foo', 'bar3')]
Łukasz Langa26d513c2010-11-10 18:57:39 +000079
80 # API access
81 L = cf.sections()
82 L.sort()
Fred Drakec6f28912002-10-25 19:40:49 +000083 eq = self.assertEqual
Fred Drake03c44a32010-02-19 06:08:41 +000084 eq(L, E)
Łukasz Langa71b37a52010-12-17 21:56:32 +000085 L = cf.items('Spacey Bar From The Beginning')
86 L.sort()
87 eq(L, F)
Fred Drake8ef67672000-09-27 22:45:25 +000088
Łukasz Langa26d513c2010-11-10 18:57:39 +000089 # mapping access
90 L = [section for section in cf]
91 L.sort()
Łukasz Langac264c092010-11-20 16:15:37 +000092 E.append(self.default_section)
Łukasz Langa26d513c2010-11-10 18:57:39 +000093 E.sort()
94 eq(L, E)
Łukasz Langa71b37a52010-12-17 21:56:32 +000095 L = cf['Spacey Bar From The Beginning'].items()
96 L = sorted(list(L))
97 eq(L, F)
98 L = cf.items()
99 L = sorted(list(L))
100 self.assertEqual(len(L), len(E))
101 for name, section in L:
102 eq(name, section.name)
103 eq(cf.defaults(), cf[self.default_section])
Łukasz Langa26d513c2010-11-10 18:57:39 +0000104
Fred Drakec6f28912002-10-25 19:40:49 +0000105 # The use of spaces in the section names serves as a
106 # regression test for SourceForge bug #583248:
107 # http://www.python.org/sf/583248
Łukasz Langa26d513c2010-11-10 18:57:39 +0000108
109 # API access
110 eq(cf.get('Foo Bar', 'foo'), 'bar1')
111 eq(cf.get('Spacey Bar', 'foo'), 'bar2')
112 eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000113 eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000114 eq(cf.get('Commented Bar', 'foo'), 'bar4')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000115 eq(cf.get('Commented Bar', 'baz'), 'qwe')
Fred Drakec6f28912002-10-25 19:40:49 +0000116 eq(cf.get('Spaces', 'key with spaces'), 'value')
117 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drakecc645b92010-09-04 04:35:34 +0000118 eq(cf.getint('Types', 'int'), 42)
119 eq(cf.get('Types', 'int'), "42")
120 self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
121 eq(cf.get('Types', 'float'), "0.44")
122 eq(cf.getboolean('Types', 'boolean'), False)
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000123 eq(cf.get('Types', '123'), 'strange but acceptable')
Fred Drake03c44a32010-02-19 06:08:41 +0000124 if self.allow_no_value:
125 eq(cf.get('NoValue', 'option-without-value'), None)
Fred Drake3d5f7e82000-12-04 16:30:40 +0000126
Łukasz Langa26d513c2010-11-10 18:57:39 +0000127 # test vars= and fallback=
128 eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
Fred Drakecc645b92010-09-04 04:35:34 +0000129 eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
130 with self.assertRaises(configparser.NoSectionError):
131 cf.get('No Such Foo Bar', 'foo')
132 with self.assertRaises(configparser.NoOptionError):
133 cf.get('Foo Bar', 'no-such-foo')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000134 eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
135 eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
136 eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
137 eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
138 eq(cf.getint('Types', 'int', fallback=18), 42)
139 eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
140 eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
Łukasz Langa71b37a52010-12-17 21:56:32 +0000141 with self.assertRaises(configparser.NoOptionError):
142 cf.getint('Types', 'no-such-int')
Fred Drakecc645b92010-09-04 04:35:34 +0000143 self.assertAlmostEqual(cf.getfloat('Types', 'float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000144 fallback=0.0), 0.44)
Fred Drakecc645b92010-09-04 04:35:34 +0000145 self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000146 fallback=0.0), 0.0)
147 eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
Łukasz Langa71b37a52010-12-17 21:56:32 +0000148 with self.assertRaises(configparser.NoOptionError):
149 cf.getfloat('Types', 'no-such-float')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000150 eq(cf.getboolean('Types', 'boolean', fallback=True), False)
151 eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
Fred Drakecc645b92010-09-04 04:35:34 +0000152 "yes") # sic!
Łukasz Langa26d513c2010-11-10 18:57:39 +0000153 eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
Łukasz Langa71b37a52010-12-17 21:56:32 +0000154 with self.assertRaises(configparser.NoOptionError):
155 cf.getboolean('Types', 'no-such-boolean')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000156 eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
Fred Drakecc645b92010-09-04 04:35:34 +0000157 if self.allow_no_value:
Łukasz Langa26d513c2010-11-10 18:57:39 +0000158 eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
Fred Drakecc645b92010-09-04 04:35:34 +0000159 eq(cf.get('NoValue', 'no-such-option-without-value',
Łukasz Langa26d513c2010-11-10 18:57:39 +0000160 fallback=False), False)
Fred Drakecc645b92010-09-04 04:35:34 +0000161
Łukasz Langa26d513c2010-11-10 18:57:39 +0000162 # mapping access
163 eq(cf['Foo Bar']['foo'], 'bar1')
164 eq(cf['Spacey Bar']['foo'], 'bar2')
Łukasz Langaa73dc9d2010-11-21 13:56:42 +0000165 section = cf['Spacey Bar From The Beginning']
166 eq(section.name, 'Spacey Bar From The Beginning')
167 self.assertIs(section.parser, cf)
168 with self.assertRaises(AttributeError):
169 section.name = 'Name is read-only'
170 with self.assertRaises(AttributeError):
171 section.parser = 'Parser is read-only'
172 eq(section['foo'], 'bar3')
173 eq(section['baz'], 'qwe')
Łukasz Langa26d513c2010-11-10 18:57:39 +0000174 eq(cf['Commented Bar']['foo'], 'bar4')
175 eq(cf['Commented Bar']['baz'], 'qwe')
176 eq(cf['Spaces']['key with spaces'], 'value')
177 eq(cf['Spaces']['another with spaces'], 'splat!')
178 eq(cf['Long Line']['foo'],
179 'this line is much, much longer than my editor\nlikes it.')
180 if self.allow_no_value:
181 eq(cf['NoValue']['option-without-value'], None)
Łukasz Langa2f0fd0f2010-12-04 17:48:18 +0000182 # test vars= and fallback=
183 eq(cf['Foo Bar'].get('foo', 'baz'), 'bar1')
184 eq(cf['Foo Bar'].get('foo', fallback='baz'), 'bar1')
185 eq(cf['Foo Bar'].get('foo', vars={'foo': 'baz'}), 'baz')
186 with self.assertRaises(KeyError):
187 cf['No Such Foo Bar']['foo']
188 with self.assertRaises(KeyError):
189 cf['Foo Bar']['no-such-foo']
190 with self.assertRaises(KeyError):
191 cf['No Such Foo Bar'].get('foo', fallback='baz')
192 eq(cf['Foo Bar'].get('no-such-foo', 'baz'), 'baz')
193 eq(cf['Foo Bar'].get('no-such-foo', fallback='baz'), 'baz')
Łukasz Langa71b37a52010-12-17 21:56:32 +0000194 eq(cf['Foo Bar'].get('no-such-foo'), None)
Łukasz Langa2f0fd0f2010-12-04 17:48:18 +0000195 eq(cf['Spacey Bar'].get('foo', None), 'bar2')
196 eq(cf['Spacey Bar'].get('foo', fallback=None), 'bar2')
197 with self.assertRaises(KeyError):
198 cf['No Such Spacey Bar'].get('foo', None)
199 eq(cf['Types'].getint('int', 18), 42)
200 eq(cf['Types'].getint('int', fallback=18), 42)
201 eq(cf['Types'].getint('no-such-int', 18), 18)
202 eq(cf['Types'].getint('no-such-int', fallback=18), 18)
203 eq(cf['Types'].getint('no-such-int', "18"), "18") # sic!
204 eq(cf['Types'].getint('no-such-int', fallback="18"), "18") # sic!
Łukasz Langa71b37a52010-12-17 21:56:32 +0000205 eq(cf['Types'].getint('no-such-int'), None)
Łukasz Langa2f0fd0f2010-12-04 17:48:18 +0000206 self.assertAlmostEqual(cf['Types'].getfloat('float', 0.0), 0.44)
207 self.assertAlmostEqual(cf['Types'].getfloat('float',
208 fallback=0.0), 0.44)
209 self.assertAlmostEqual(cf['Types'].getfloat('no-such-float', 0.0), 0.0)
210 self.assertAlmostEqual(cf['Types'].getfloat('no-such-float',
211 fallback=0.0), 0.0)
212 eq(cf['Types'].getfloat('no-such-float', "0.0"), "0.0") # sic!
213 eq(cf['Types'].getfloat('no-such-float', fallback="0.0"), "0.0") # sic!
Łukasz Langa71b37a52010-12-17 21:56:32 +0000214 eq(cf['Types'].getfloat('no-such-float'), None)
Łukasz Langa2f0fd0f2010-12-04 17:48:18 +0000215 eq(cf['Types'].getboolean('boolean', True), False)
216 eq(cf['Types'].getboolean('boolean', fallback=True), False)
217 eq(cf['Types'].getboolean('no-such-boolean', "yes"), "yes") # sic!
218 eq(cf['Types'].getboolean('no-such-boolean', fallback="yes"),
219 "yes") # sic!
220 eq(cf['Types'].getboolean('no-such-boolean', True), True)
221 eq(cf['Types'].getboolean('no-such-boolean', fallback=True), True)
Łukasz Langa71b37a52010-12-17 21:56:32 +0000222 eq(cf['Types'].getboolean('no-such-boolean'), None)
Łukasz Langa2f0fd0f2010-12-04 17:48:18 +0000223 if self.allow_no_value:
224 eq(cf['NoValue'].get('option-without-value', False), None)
225 eq(cf['NoValue'].get('option-without-value', fallback=False), None)
226 eq(cf['NoValue'].get('no-such-option-without-value', False), False)
227 eq(cf['NoValue'].get('no-such-option-without-value',
228 fallback=False), False)
Łukasz Langa26d513c2010-11-10 18:57:39 +0000229
Łukasz Langa71b37a52010-12-17 21:56:32 +0000230 # Make sure the right things happen for remove_section() and
231 # remove_option(); added to include check for SourceForge bug #123324.
Łukasz Langa26d513c2010-11-10 18:57:39 +0000232
Łukasz Langa71b37a52010-12-17 21:56:32 +0000233 cf[self.default_section]['this_value'] = '1'
234 cf[self.default_section]['that_value'] = '2'
235
236 # API access
237 self.assertTrue(cf.remove_section('Spaces'))
238 self.assertFalse(cf.has_option('Spaces', 'key with spaces'))
239 self.assertFalse(cf.remove_section('Spaces'))
240 self.assertFalse(cf.remove_section(self.default_section))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000241 self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000242 "remove_option() failed to report existence of option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000243 self.assertFalse(cf.has_option('Foo Bar', 'foo'),
Fred Drakec6f28912002-10-25 19:40:49 +0000244 "remove_option() failed to remove option")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000245 self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
Mark Dickinson934896d2009-02-21 20:59:32 +0000246 "remove_option() failed to report non-existence of option"
Fred Drakec6f28912002-10-25 19:40:49 +0000247 " that was removed")
Łukasz Langa71b37a52010-12-17 21:56:32 +0000248 self.assertTrue(cf.has_option('Foo Bar', 'this_value'))
249 self.assertFalse(cf.remove_option('Foo Bar', 'this_value'))
250 self.assertTrue(cf.remove_option(self.default_section, 'this_value'))
251 self.assertFalse(cf.has_option('Foo Bar', 'this_value'))
252 self.assertFalse(cf.remove_option(self.default_section, 'this_value'))
Fred Drakec6f28912002-10-25 19:40:49 +0000253
Michael Foordbd6c0792010-07-25 23:09:25 +0000254 with self.assertRaises(configparser.NoSectionError) as cm:
255 cf.remove_option('No Such Section', 'foo')
256 self.assertEqual(cm.exception.args, ('No Such Section',))
Fred Drakec6f28912002-10-25 19:40:49 +0000257
258 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +0000259 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +0000260
Łukasz Langa26d513c2010-11-10 18:57:39 +0000261 # mapping access
Łukasz Langa71b37a52010-12-17 21:56:32 +0000262 del cf['Types']
263 self.assertFalse('Types' in cf)
264 with self.assertRaises(KeyError):
265 del cf['Types']
266 with self.assertRaises(ValueError):
267 del cf[self.default_section]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000268 del cf['Spacey Bar']['foo']
269 self.assertFalse('foo' in cf['Spacey Bar'])
270 with self.assertRaises(KeyError):
271 del cf['Spacey Bar']['foo']
Łukasz Langa71b37a52010-12-17 21:56:32 +0000272 self.assertTrue('that_value' in cf['Spacey Bar'])
273 with self.assertRaises(KeyError):
274 del cf['Spacey Bar']['that_value']
275 del cf[self.default_section]['that_value']
276 self.assertFalse('that_value' in cf['Spacey Bar'])
277 with self.assertRaises(KeyError):
278 del cf[self.default_section]['that_value']
Łukasz Langa26d513c2010-11-10 18:57:39 +0000279 with self.assertRaises(KeyError):
280 del cf['No Such Section']['foo']
281
Łukasz Langa71b37a52010-12-17 21:56:32 +0000282 # Don't add new asserts below in this method as most of the options
283 # and sections are now removed.
284
Fred Drakea4923622010-08-09 12:52:45 +0000285 def test_basic(self):
286 config_string = """\
287[Foo Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000288foo{0[0]}bar1
Fred Drakea4923622010-08-09 12:52:45 +0000289[Spacey Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000290foo {0[0]} bar2
Fred Drakea4923622010-08-09 12:52:45 +0000291[Spacey Bar From The Beginning]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000292 foo {0[0]} bar3
Fred Drakea4923622010-08-09 12:52:45 +0000293 baz {0[0]} qwe
294[Commented Bar]
Łukasz Langa26d513c2010-11-10 18:57:39 +0000295foo{0[1]} bar4 {1[1]} comment
Fred Drakea4923622010-08-09 12:52:45 +0000296baz{0[0]}qwe {1[0]}another one
297[Long Line]
298foo{0[1]} this line is much, much longer than my editor
299 likes it.
300[Section\\with$weird%characters[\t]
301[Internationalized Stuff]
302foo[bg]{0[1]} Bulgarian
303foo{0[0]}Default
304foo[en]{0[0]}English
305foo[de]{0[0]}Deutsch
306[Spaces]
307key with spaces {0[1]} value
308another with spaces {0[0]} splat!
Fred Drakecc645b92010-09-04 04:35:34 +0000309[Types]
310int {0[1]} 42
311float {0[0]} 0.44
312boolean {0[0]} NO
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000313123 {0[1]} strange but acceptable
Fred Drakea4923622010-08-09 12:52:45 +0000314""".format(self.delimiters, self.comment_prefixes)
315 if self.allow_no_value:
316 config_string += (
317 "[NoValue]\n"
318 "option-without-value\n"
319 )
320 cf = self.fromstring(config_string)
321 self.basic_test(cf)
322 if self.strict:
323 with self.assertRaises(configparser.DuplicateOptionError):
324 cf.read_string(textwrap.dedent("""\
325 [Duplicate Options Here]
326 option {0[0]} with a value
327 option {0[1]} with another value
328 """.format(self.delimiters)))
329 with self.assertRaises(configparser.DuplicateSectionError):
330 cf.read_string(textwrap.dedent("""\
331 [And Now For Something]
332 completely different {0[0]} True
333 [And Now For Something]
334 the larch {0[1]} 1
335 """.format(self.delimiters)))
336 else:
337 cf.read_string(textwrap.dedent("""\
338 [Duplicate Options Here]
339 option {0[0]} with a value
340 option {0[1]} with another value
341 """.format(self.delimiters)))
342
343 cf.read_string(textwrap.dedent("""\
344 [And Now For Something]
345 completely different {0[0]} True
346 [And Now For Something]
347 the larch {0[1]} 1
348 """.format(self.delimiters)))
349
350 def test_basic_from_dict(self):
351 config = {
352 "Foo Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000353 "foo": "bar1",
Fred Drakea4923622010-08-09 12:52:45 +0000354 },
355 "Spacey Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000356 "foo": "bar2",
Fred Drakea4923622010-08-09 12:52:45 +0000357 },
358 "Spacey Bar From The Beginning": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000359 "foo": "bar3",
Fred Drakea4923622010-08-09 12:52:45 +0000360 "baz": "qwe",
361 },
362 "Commented Bar": {
Łukasz Langa26d513c2010-11-10 18:57:39 +0000363 "foo": "bar4",
Fred Drakea4923622010-08-09 12:52:45 +0000364 "baz": "qwe",
365 },
366 "Long Line": {
367 "foo": "this line is much, much longer than my editor\nlikes "
368 "it.",
369 },
370 "Section\\with$weird%characters[\t": {
371 },
372 "Internationalized Stuff": {
373 "foo[bg]": "Bulgarian",
374 "foo": "Default",
375 "foo[en]": "English",
376 "foo[de]": "Deutsch",
377 },
378 "Spaces": {
379 "key with spaces": "value",
380 "another with spaces": "splat!",
Fred Drakecc645b92010-09-04 04:35:34 +0000381 },
382 "Types": {
383 "int": 42,
384 "float": 0.44,
385 "boolean": False,
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000386 123: "strange but acceptable",
Fred Drakecc645b92010-09-04 04:35:34 +0000387 },
Fred Drakea4923622010-08-09 12:52:45 +0000388 }
389 if self.allow_no_value:
390 config.update({
391 "NoValue": {
392 "option-without-value": None,
393 }
394 })
395 cf = self.newconfig()
396 cf.read_dict(config)
397 self.basic_test(cf)
398 if self.strict:
Łukasz Langa71b37a52010-12-17 21:56:32 +0000399 with self.assertRaises(configparser.DuplicateSectionError):
400 cf.read_dict({
401 '1': {'key': 'value'},
402 1: {'key2': 'value2'},
403 })
Fred Drakea4923622010-08-09 12:52:45 +0000404 with self.assertRaises(configparser.DuplicateOptionError):
405 cf.read_dict({
406 "Duplicate Options Here": {
407 'option': 'with a value',
408 'OPTION': 'with another value',
409 },
410 })
411 else:
412 cf.read_dict({
Łukasz Langa71b37a52010-12-17 21:56:32 +0000413 'section': {'key': 'value'},
414 'SECTION': {'key2': 'value2'},
415 })
416 cf.read_dict({
Fred Drakea4923622010-08-09 12:52:45 +0000417 "Duplicate Options Here": {
418 'option': 'with a value',
419 'OPTION': 'with another value',
420 },
421 })
422
Fred Drakec6f28912002-10-25 19:40:49 +0000423 def test_case_sensitivity(self):
424 cf = self.newconfig()
425 cf.add_section("A")
426 cf.add_section("a")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000427 cf.add_section("B")
Fred Drakec6f28912002-10-25 19:40:49 +0000428 L = cf.sections()
429 L.sort()
430 eq = self.assertEqual
Łukasz Langa26d513c2010-11-10 18:57:39 +0000431 eq(L, ["A", "B", "a"])
Fred Drakec6f28912002-10-25 19:40:49 +0000432 cf.set("a", "B", "value")
433 eq(cf.options("a"), ["b"])
434 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +0000435 "could not locate option, expecting case-insensitive option names")
Łukasz Langa26d513c2010-11-10 18:57:39 +0000436 with self.assertRaises(configparser.NoSectionError):
437 # section names are case-sensitive
438 cf.set("b", "A", "value")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000439 self.assertTrue(cf.has_option("a", "b"))
Łukasz Langa71b37a52010-12-17 21:56:32 +0000440 self.assertFalse(cf.has_option("b", "b"))
Fred Drakec6f28912002-10-25 19:40:49 +0000441 cf.set("A", "A-B", "A-B value")
442 for opt in ("a-b", "A-b", "a-B", "A-B"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000443 self.assertTrue(
Fred Drakec6f28912002-10-25 19:40:49 +0000444 cf.has_option("A", opt),
445 "has_option() returned false for option which should exist")
446 eq(cf.options("A"), ["a-b"])
447 eq(cf.options("a"), ["b"])
448 cf.remove_option("a", "B")
449 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000450
Fred Drakec6f28912002-10-25 19:40:49 +0000451 # SF bug #432369:
452 cf = self.fromstring(
Łukasz Langa26d513c2010-11-10 18:57:39 +0000453 "[MySection]\nOption{} first line \n\tsecond line \n".format(
Georg Brandl96a60ae2010-07-28 13:13:46 +0000454 self.delimiters[0]))
Fred Drakec6f28912002-10-25 19:40:49 +0000455 eq(cf.options("MySection"), ["option"])
456 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000457
Fred Drakec6f28912002-10-25 19:40:49 +0000458 # SF bug #561822:
Georg Brandl96a60ae2010-07-28 13:13:46 +0000459 cf = self.fromstring("[section]\n"
460 "nekey{}nevalue\n".format(self.delimiters[0]),
Fred Drakec6f28912002-10-25 19:40:49 +0000461 defaults={"key":"value"})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000462 self.assertTrue(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000463
Fred Drake3c823aa2001-02-26 21:55:34 +0000464
Łukasz Langa26d513c2010-11-10 18:57:39 +0000465 def test_case_sensitivity_mapping_access(self):
466 cf = self.newconfig()
467 cf["A"] = {}
468 cf["a"] = {"B": "value"}
469 cf["B"] = {}
470 L = [section for section in cf]
471 L.sort()
472 eq = self.assertEqual
Ezio Melotti263cbdf2010-11-29 02:02:10 +0000473 elem_eq = self.assertCountEqual
Łukasz Langac264c092010-11-20 16:15:37 +0000474 eq(L, sorted(["A", "B", self.default_section, "a"]))
Łukasz Langa26d513c2010-11-10 18:57:39 +0000475 eq(cf["a"].keys(), {"b"})
476 eq(cf["a"]["b"], "value",
477 "could not locate option, expecting case-insensitive option names")
478 with self.assertRaises(KeyError):
479 # section names are case-sensitive
480 cf["b"]["A"] = "value"
481 self.assertTrue("b" in cf["a"])
482 cf["A"]["A-B"] = "A-B value"
483 for opt in ("a-b", "A-b", "a-B", "A-B"):
484 self.assertTrue(
485 opt in cf["A"],
486 "has_option() returned false for option which should exist")
487 eq(cf["A"].keys(), {"a-b"})
488 eq(cf["a"].keys(), {"b"})
489 del cf["a"]["B"]
490 elem_eq(cf["a"].keys(), {})
491
492 # SF bug #432369:
493 cf = self.fromstring(
494 "[MySection]\nOption{} first line \n\tsecond line \n".format(
495 self.delimiters[0]))
496 eq(cf["MySection"].keys(), {"option"})
497 eq(cf["MySection"]["Option"], "first line\nsecond line")
498
499 # SF bug #561822:
500 cf = self.fromstring("[section]\n"
501 "nekey{}nevalue\n".format(self.delimiters[0]),
502 defaults={"key":"value"})
503 self.assertTrue("Key" in cf["section"])
504
David Goodger68a1abd2004-10-03 15:40:25 +0000505 def test_default_case_sensitivity(self):
506 cf = self.newconfig({"foo": "Bar"})
507 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000508 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000509 "could not locate option, expecting case-insensitive option names")
510 cf = self.newconfig({"Foo": "Bar"})
511 self.assertEqual(
Łukasz Langac264c092010-11-20 16:15:37 +0000512 cf.get(self.default_section, "Foo"), "Bar",
David Goodger68a1abd2004-10-03 15:40:25 +0000513 "could not locate option, expecting case-insensitive defaults")
514
Fred Drakec6f28912002-10-25 19:40:49 +0000515 def test_parse_errors(self):
Fred Drakea4923622010-08-09 12:52:45 +0000516 cf = self.newconfig()
517 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000518 "[Foo]\n"
519 "{}val-without-opt-name\n".format(self.delimiters[0]))
Fred Drakea4923622010-08-09 12:52:45 +0000520 self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000521 "[Foo]\n"
522 "{}val-without-opt-name\n".format(self.delimiters[1]))
Fred Drakea4923622010-08-09 12:52:45 +0000523 e = self.parse_error(cf, configparser.MissingSectionHeaderError,
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000524 "No Section!\n")
Michael Foordbd6c0792010-07-25 23:09:25 +0000525 self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
Georg Brandl96a60ae2010-07-28 13:13:46 +0000526 if not self.allow_no_value:
Fred Drakea4923622010-08-09 12:52:45 +0000527 e = self.parse_error(cf, configparser.ParsingError,
Georg Brandl96a60ae2010-07-28 13:13:46 +0000528 "[Foo]\n wrong-indent\n")
529 self.assertEqual(e.args, ('<???>',))
Florent Xicluna42d54452010-09-22 22:35:38 +0000530 # read_file on a real file
531 tricky = support.findfile("cfgparser.3")
532 if self.delimiters[0] == '=':
533 error = configparser.ParsingError
534 expected = (tricky,)
535 else:
536 error = configparser.MissingSectionHeaderError
537 expected = (tricky, 1,
538 ' # INI with as many tricky parts as possible\n')
Florent Xiclunad12a4202010-09-23 00:46:13 +0000539 with open(tricky, encoding='utf-8') as f:
Florent Xicluna42d54452010-09-22 22:35:38 +0000540 e = self.parse_error(cf, error, f)
541 self.assertEqual(e.args, expected)
Fred Drake168bead2001-10-08 17:13:12 +0000542
Fred Drakea4923622010-08-09 12:52:45 +0000543 def parse_error(self, cf, exc, src):
Florent Xicluna42d54452010-09-22 22:35:38 +0000544 if hasattr(src, 'readline'):
545 sio = src
546 else:
547 sio = io.StringIO(src)
Michael Foordbd6c0792010-07-25 23:09:25 +0000548 with self.assertRaises(exc) as cm:
Fred Drakea4923622010-08-09 12:52:45 +0000549 cf.read_file(sio)
Michael Foordbd6c0792010-07-25 23:09:25 +0000550 return cm.exception
Fred Drake168bead2001-10-08 17:13:12 +0000551
Fred Drakec6f28912002-10-25 19:40:49 +0000552 def test_query_errors(self):
553 cf = self.newconfig()
554 self.assertEqual(cf.sections(), [],
555 "new ConfigParser should have no defined sections")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000556 self.assertFalse(cf.has_section("Foo"),
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000557 "new ConfigParser should have no acknowledged "
558 "sections")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000559 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000560 cf.options("Foo")
Georg Brandl96a60ae2010-07-28 13:13:46 +0000561 with self.assertRaises(configparser.NoSectionError):
Michael Foordbd6c0792010-07-25 23:09:25 +0000562 cf.set("foo", "bar", "value")
Fred Drakea4923622010-08-09 12:52:45 +0000563 e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000564 self.assertEqual(e.args, ("foo",))
Fred Drakec6f28912002-10-25 19:40:49 +0000565 cf.add_section("foo")
Fred Drakea4923622010-08-09 12:52:45 +0000566 e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
Michael Foordbd6c0792010-07-25 23:09:25 +0000567 self.assertEqual(e.args, ("bar", "foo"))
Fred Drake8ef67672000-09-27 22:45:25 +0000568
Fred Drakea4923622010-08-09 12:52:45 +0000569 def get_error(self, cf, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000570 try:
Fred Drakea4923622010-08-09 12:52:45 +0000571 cf.get(section, option)
Guido van Rossumb940e112007-01-10 16:19:56 +0000572 except exc as e:
Fred Drake54782192002-12-31 06:57:25 +0000573 return e
574 else:
575 self.fail("expected exception type %s.%s"
576 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000577
Fred Drakec6f28912002-10-25 19:40:49 +0000578 def test_boolean(self):
579 cf = self.fromstring(
580 "[BOOLTEST]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000581 "T1{equals}1\n"
582 "T2{equals}TRUE\n"
583 "T3{equals}True\n"
584 "T4{equals}oN\n"
585 "T5{equals}yes\n"
586 "F1{equals}0\n"
587 "F2{equals}FALSE\n"
588 "F3{equals}False\n"
589 "F4{equals}oFF\n"
590 "F5{equals}nO\n"
591 "E1{equals}2\n"
592 "E2{equals}foo\n"
593 "E3{equals}-1\n"
594 "E4{equals}0.1\n"
595 "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
Fred Drakec6f28912002-10-25 19:40:49 +0000596 )
597 for x in range(1, 5):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000598 self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
599 self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
Fred Drakec6f28912002-10-25 19:40:49 +0000600 self.assertRaises(ValueError,
601 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000602
Fred Drakec6f28912002-10-25 19:40:49 +0000603 def test_weird_errors(self):
604 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000605 cf.add_section("Foo")
Michael Foordbd6c0792010-07-25 23:09:25 +0000606 with self.assertRaises(configparser.DuplicateSectionError) as cm:
607 cf.add_section("Foo")
Fred Drakea4923622010-08-09 12:52:45 +0000608 e = cm.exception
609 self.assertEqual(str(e), "Section 'Foo' already exists")
610 self.assertEqual(e.args, ("Foo", None, None))
611
612 if self.strict:
613 with self.assertRaises(configparser.DuplicateSectionError) as cm:
614 cf.read_string(textwrap.dedent("""\
615 [Foo]
616 will this be added{equals}True
617 [Bar]
618 what about this{equals}True
619 [Foo]
620 oops{equals}this won't
621 """.format(equals=self.delimiters[0])), source='<foo-bar>')
622 e = cm.exception
623 self.assertEqual(str(e), "While reading from <foo-bar> [line 5]: "
624 "section 'Foo' already exists")
625 self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
626
627 with self.assertRaises(configparser.DuplicateOptionError) as cm:
628 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
629 e = cm.exception
630 self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
631 "in section 'Bar' already exists")
632 self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
Fred Drakec6f28912002-10-25 19:40:49 +0000633
634 def test_write(self):
Fred Drake03c44a32010-02-19 06:08:41 +0000635 config_string = (
Fred Drakec6f28912002-10-25 19:40:49 +0000636 "[Long Line]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000637 "foo{0[0]} this line is much, much longer than my editor\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000638 " likes it.\n"
Łukasz Langac264c092010-11-20 16:15:37 +0000639 "[{default_section}]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000640 "foo{0[1]} another very\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000641 " long line\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000642 "[Long Line - With Comments!]\n"
643 "test {0[1]} we {comment} can\n"
644 " also {comment} place\n"
645 " comments {comment} in\n"
646 " multiline {comment} values"
Łukasz Langac264c092010-11-20 16:15:37 +0000647 "\n".format(self.delimiters, comment=self.comment_prefixes[0],
648 default_section=self.default_section)
Fred Drakec6f28912002-10-25 19:40:49 +0000649 )
Fred Drake03c44a32010-02-19 06:08:41 +0000650 if self.allow_no_value:
651 config_string += (
652 "[Valueless]\n"
653 "option-without-value\n"
654 )
655
656 cf = self.fromstring(config_string)
Łukasz Langa71b37a52010-12-17 21:56:32 +0000657 for space_around_delimiters in (True, False):
658 output = io.StringIO()
659 cf.write(output, space_around_delimiters=space_around_delimiters)
660 delimiter = self.delimiters[0]
661 if space_around_delimiters:
662 delimiter = " {} ".format(delimiter)
663 expect_string = (
664 "[{default_section}]\n"
665 "foo{equals}another very\n"
666 "\tlong line\n"
Fred Drake03c44a32010-02-19 06:08:41 +0000667 "\n"
Łukasz Langa71b37a52010-12-17 21:56:32 +0000668 "[Long Line]\n"
669 "foo{equals}this line is much, much longer than my editor\n"
670 "\tlikes it.\n"
671 "\n"
672 "[Long Line - With Comments!]\n"
673 "test{equals}we\n"
674 "\talso\n"
675 "\tcomments\n"
676 "\tmultiline\n"
677 "\n".format(equals=delimiter,
678 default_section=self.default_section)
Fred Drake03c44a32010-02-19 06:08:41 +0000679 )
Łukasz Langa71b37a52010-12-17 21:56:32 +0000680 if self.allow_no_value:
681 expect_string += (
682 "[Valueless]\n"
683 "option-without-value\n"
684 "\n"
685 )
686 self.assertEqual(output.getvalue(), expect_string)
Fred Drakec6f28912002-10-25 19:40:49 +0000687
Fred Drakeabc086f2004-05-18 03:29:52 +0000688 def test_set_string_types(self):
689 cf = self.fromstring("[sect]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000690 "option1{eq}foo\n".format(eq=self.delimiters[0]))
Fred Drakeabc086f2004-05-18 03:29:52 +0000691 # Check that we don't get an exception when setting values in
692 # an existing section using strings:
693 class mystr(str):
694 pass
695 cf.set("sect", "option1", "splat")
696 cf.set("sect", "option1", mystr("splat"))
697 cf.set("sect", "option2", "splat")
698 cf.set("sect", "option2", mystr("splat"))
Walter Dörwald5de48bd2007-06-11 21:38:39 +0000699 cf.set("sect", "option1", "splat")
700 cf.set("sect", "option2", "splat")
Fred Drakeabc086f2004-05-18 03:29:52 +0000701
Fred Drake82903142004-05-18 04:24:02 +0000702 def test_read_returns_file_list(self):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000703 if self.delimiters[0] != '=':
704 # skip reading the file if we're using an incompatible format
705 return
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000706 file1 = support.findfile("cfgparser.1")
Fred Drake82903142004-05-18 04:24:02 +0000707 # check when we pass a mix of readable and non-readable files:
708 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000709 parsed_files = cf.read([file1, "nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000710 self.assertEqual(parsed_files, [file1])
711 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
712 # check when we pass only a filename:
713 cf = self.newconfig()
714 parsed_files = cf.read(file1)
715 self.assertEqual(parsed_files, [file1])
716 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
717 # check when we pass only missing files:
718 cf = self.newconfig()
Mark Dickinson934896d2009-02-21 20:59:32 +0000719 parsed_files = cf.read(["nonexistent-file"])
Fred Drake82903142004-05-18 04:24:02 +0000720 self.assertEqual(parsed_files, [])
721 # check when we pass no files:
722 cf = self.newconfig()
723 parsed_files = cf.read([])
724 self.assertEqual(parsed_files, [])
725
Fred Drakec6f28912002-10-25 19:40:49 +0000726 # shared by subclasses
727 def get_interpolation_config(self):
728 return self.fromstring(
729 "[Foo]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000730 "bar{equals}something %(with1)s interpolation (1 step)\n"
731 "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
732 "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
733 "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
734 "with11{equals}%(with10)s\n"
735 "with10{equals}%(with9)s\n"
736 "with9{equals}%(with8)s\n"
737 "with8{equals}%(With7)s\n"
738 "with7{equals}%(WITH6)s\n"
739 "with6{equals}%(with5)s\n"
740 "With5{equals}%(with4)s\n"
741 "WITH4{equals}%(with3)s\n"
742 "with3{equals}%(with2)s\n"
743 "with2{equals}%(with1)s\n"
744 "with1{equals}with\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000745 "\n"
746 "[Mutual Recursion]\n"
Georg Brandl96a60ae2010-07-28 13:13:46 +0000747 "foo{equals}%(bar)s\n"
748 "bar{equals}%(foo)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000749 "\n"
750 "[Interpolation Error]\n"
Fred Drake54782192002-12-31 06:57:25 +0000751 # no definition for 'reference'
Łukasz Langa5c863392010-11-21 13:41:35 +0000752 "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
Fred Drake95b96d32001-02-12 17:23:20 +0000753
Fred Drake98e3b292002-10-25 20:42:44 +0000754 def check_items_config(self, expected):
Łukasz Langa71b37a52010-12-17 21:56:32 +0000755 cf = self.fromstring("""
756 [section]
757 name {0[0]} %(value)s
758 key{0[1]} |%(name)s|
759 getdefault{0[1]} |%(default)s|
760 """.format(self.delimiters), defaults={"default": "<default>"})
761 L = list(cf.items("section", vars={'value': 'value'}))
Fred Drake98e3b292002-10-25 20:42:44 +0000762 L.sort()
763 self.assertEqual(L, expected)
Łukasz Langa71b37a52010-12-17 21:56:32 +0000764 with self.assertRaises(configparser.NoSectionError):
765 cf.items("no such section")
Fred Drake98e3b292002-10-25 20:42:44 +0000766
Fred Drake8ef67672000-09-27 22:45:25 +0000767
Fred Drakea4923622010-08-09 12:52:45 +0000768class StrictTestCase(BasicTestCase):
769 config_class = configparser.RawConfigParser
770 strict = True
771
772
Georg Brandl96a60ae2010-07-28 13:13:46 +0000773class ConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000774 config_class = configparser.ConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000775
776 def test_interpolation(self):
777 cf = self.get_interpolation_config()
778 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000779 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
780 eq(cf.get("Foo", "bar9"),
781 "something with lots of interpolation (9 steps)")
782 eq(cf.get("Foo", "bar10"),
783 "something with lots of interpolation (10 steps)")
Fred Drakea4923622010-08-09 12:52:45 +0000784 e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
Łukasz Langa7f64c8a2010-12-16 01:16:22 +0000785 if self.interpolation == configparser._UNSET:
786 self.assertEqual(e.args, ("bar11", "Foo", "%(with1)s"))
787 elif isinstance(self.interpolation, configparser.LegacyInterpolation):
788 self.assertEqual(e.args, ("bar11", "Foo",
789 "something %(with11)s lots of interpolation (11 steps)"))
Fred Drake95b96d32001-02-12 17:23:20 +0000790
Fred Drake54782192002-12-31 06:57:25 +0000791 def test_interpolation_missing_value(self):
Fred Drakea4923622010-08-09 12:52:45 +0000792 cf = self.get_interpolation_config()
793 e = self.get_error(cf, configparser.InterpolationMissingOptionError,
Fred Drake54782192002-12-31 06:57:25 +0000794 "Interpolation Error", "name")
795 self.assertEqual(e.reference, "reference")
796 self.assertEqual(e.section, "Interpolation Error")
797 self.assertEqual(e.option, "name")
Łukasz Langa7f64c8a2010-12-16 01:16:22 +0000798 if self.interpolation == configparser._UNSET:
799 self.assertEqual(e.args, ('name', 'Interpolation Error',
800 '', 'reference'))
801 elif isinstance(self.interpolation, configparser.LegacyInterpolation):
802 self.assertEqual(e.args, ('name', 'Interpolation Error',
803 '%(reference)s', 'reference'))
Fred Drake54782192002-12-31 06:57:25 +0000804
Fred Drake98e3b292002-10-25 20:42:44 +0000805 def test_items(self):
806 self.check_items_config([('default', '<default>'),
807 ('getdefault', '|<default>|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000808 ('key', '|value|'),
Łukasz Langa71b37a52010-12-17 21:56:32 +0000809 ('name', 'value'),
810 ('value', 'value')])
Fred Drake98e3b292002-10-25 20:42:44 +0000811
Łukasz Langa7f64c8a2010-12-16 01:16:22 +0000812 def test_safe_interpolation(self):
813 # See http://www.python.org/sf/511737
814 cf = self.fromstring("[section]\n"
815 "option1{eq}xxx\n"
816 "option2{eq}%(option1)s/xxx\n"
817 "ok{eq}%(option1)s/%%s\n"
818 "not_ok{eq}%(option2)s/%%s".format(
819 eq=self.delimiters[0]))
820 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
821 if self.interpolation == configparser._UNSET:
822 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
823 elif isinstance(self.interpolation, configparser.LegacyInterpolation):
824 with self.assertRaises(TypeError):
825 cf.get("section", "not_ok")
826
827 def test_set_malformatted_interpolation(self):
828 cf = self.fromstring("[sect]\n"
829 "option1{eq}foo\n".format(eq=self.delimiters[0]))
830
831 self.assertEqual(cf.get('sect', "option1"), "foo")
832
833 self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
834 self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
835 self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
836
837 self.assertEqual(cf.get('sect', "option1"), "foo")
838
839 # bug #5741: double percents are *not* malformed
840 cf.set("sect", "option2", "foo%%bar")
841 self.assertEqual(cf.get("sect", "option2"), "foo%bar")
842
David Goodger1cbf2062004-10-03 15:55:09 +0000843 def test_set_nonstring_types(self):
Łukasz Langa7f64c8a2010-12-16 01:16:22 +0000844 cf = self.fromstring("[sect]\n"
845 "option1{eq}foo\n".format(eq=self.delimiters[0]))
846 # Check that we get a TypeError when setting non-string values
847 # in an existing section:
848 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
849 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
850 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
851 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
852 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
853 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
854 self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
855 self.assertRaises(TypeError, cf.add_section, 123)
856
857 def test_add_section_default(self):
David Goodger1cbf2062004-10-03 15:55:09 +0000858 cf = self.newconfig()
Łukasz Langa7f64c8a2010-12-16 01:16:22 +0000859 self.assertRaises(ValueError, cf.add_section, self.default_section)
860
861class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase):
862 config_class = configparser.ConfigParser
863 interpolation = configparser.LegacyInterpolation()
864
865 def test_set_malformatted_interpolation(self):
866 cf = self.fromstring("[sect]\n"
867 "option1{eq}foo\n".format(eq=self.delimiters[0]))
868
869 self.assertEqual(cf.get('sect', "option1"), "foo")
870
871 cf.set("sect", "option1", "%foo")
872 self.assertEqual(cf.get('sect', "option1"), "%foo")
873 cf.set("sect", "option1", "foo%")
874 self.assertEqual(cf.get('sect', "option1"), "foo%")
875 cf.set("sect", "option1", "f%oo")
876 self.assertEqual(cf.get('sect', "option1"), "f%oo")
877
878 # bug #5741: double percents are *not* malformed
879 cf.set("sect", "option2", "foo%%bar")
880 self.assertEqual(cf.get("sect", "option2"), "foo%%bar")
David Goodger1cbf2062004-10-03 15:55:09 +0000881
Georg Brandl96a60ae2010-07-28 13:13:46 +0000882class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
883 delimiters = (':=', '$')
884 comment_prefixes = ('//', '"')
Łukasz Langab25a7912010-12-17 01:32:29 +0000885 inline_comment_prefixes = ('//', '"')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000886
Łukasz Langac264c092010-11-20 16:15:37 +0000887class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
888 default_section = 'general'
889
Georg Brandl96a60ae2010-07-28 13:13:46 +0000890class MultilineValuesTestCase(BasicTestCase):
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000891 config_class = configparser.ConfigParser
892 wonderful_spam = ("I'm having spam spam spam spam "
893 "spam spam spam beaked beans spam "
894 "spam spam and spam!").replace(' ', '\t\n')
895
896 def setUp(self):
897 cf = self.newconfig()
898 for i in range(100):
899 s = 'section{}'.format(i)
900 cf.add_section(s)
901 for j in range(10):
902 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
903 with open(support.TESTFN, 'w') as f:
904 cf.write(f)
905
906 def tearDown(self):
907 os.unlink(support.TESTFN)
908
909 def test_dominating_multiline_values(self):
910 # We're reading from file because this is where the code changed
911 # during performance updates in Python 3.2
912 cf_from_file = self.newconfig()
913 with open(support.TESTFN) as f:
Fred Drakea4923622010-08-09 12:52:45 +0000914 cf_from_file.read_file(f)
Brian Curtin9a27b0c2010-07-26 00:27:10 +0000915 self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
916 self.wonderful_spam.replace('\t\n', '\n'))
Fred Drake8ef67672000-09-27 22:45:25 +0000917
Georg Brandl96a60ae2010-07-28 13:13:46 +0000918class RawConfigParserTestCase(BasicTestCase):
Alexandre Vassalotti1d1eaa42008-05-14 22:59:42 +0000919 config_class = configparser.RawConfigParser
Fred Drakec6f28912002-10-25 19:40:49 +0000920
921 def test_interpolation(self):
922 cf = self.get_interpolation_config()
923 eq = self.assertEqual
Fred Drakec6f28912002-10-25 19:40:49 +0000924 eq(cf.get("Foo", "bar"),
925 "something %(with1)s interpolation (1 step)")
926 eq(cf.get("Foo", "bar9"),
927 "something %(with9)s lots of interpolation (9 steps)")
928 eq(cf.get("Foo", "bar10"),
929 "something %(with10)s lots of interpolation (10 steps)")
930 eq(cf.get("Foo", "bar11"),
931 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000932
Fred Drake98e3b292002-10-25 20:42:44 +0000933 def test_items(self):
934 self.check_items_config([('default', '<default>'),
935 ('getdefault', '|%(default)s|'),
Fred Drake98e3b292002-10-25 20:42:44 +0000936 ('key', '|%(name)s|'),
Łukasz Langa71b37a52010-12-17 21:56:32 +0000937 ('name', '%(value)s'),
938 ('value', 'value')])
Fred Drake98e3b292002-10-25 20:42:44 +0000939
David Goodger1cbf2062004-10-03 15:55:09 +0000940 def test_set_nonstring_types(self):
941 cf = self.newconfig()
942 cf.add_section('non-string')
943 cf.set('non-string', 'int', 1)
944 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
945 cf.set('non-string', 'dict', {'pi': 3.14159})
946 self.assertEqual(cf.get('non-string', 'int'), 1)
947 self.assertEqual(cf.get('non-string', 'list'),
948 [0, 1, 1, 2, 3, 5, 8, 13])
949 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
Łukasz Langa2cf9ddb2010-12-04 12:46:01 +0000950 cf.add_section(123)
951 cf.set(123, 'this is sick', True)
952 self.assertEqual(cf.get(123, 'this is sick'), True)
953 if cf._dict.__class__ is configparser._default_dict:
954 # would not work for SortedDict; only checking for the most common
955 # default dictionary (OrderedDict)
956 cf.optionxform = lambda x: x
957 cf.set('non-string', 1, 1)
958 self.assertEqual(cf.get('non-string', 1), 1)
Tim Petersab9b32c2004-10-03 18:35:19 +0000959
Georg Brandl96a60ae2010-07-28 13:13:46 +0000960class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
961 delimiters = (':=', '$')
962 comment_prefixes = ('//', '"')
Łukasz Langab25a7912010-12-17 01:32:29 +0000963 inline_comment_prefixes = ('//', '"')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000964
Łukasz Langab25a7912010-12-17 01:32:29 +0000965class RawConfigParserTestSambaConf(CfgParserTestCaseClass):
Georg Brandl96a60ae2010-07-28 13:13:46 +0000966 config_class = configparser.RawConfigParser
Łukasz Langab25a7912010-12-17 01:32:29 +0000967 comment_prefixes = ('#', ';', '----')
968 inline_comment_prefixes = ('//',)
Georg Brandl96a60ae2010-07-28 13:13:46 +0000969 empty_lines_in_values = False
970
971 def test_reading(self):
972 smbconf = support.findfile("cfgparser.2")
973 # check when we pass a mix of readable and non-readable files:
974 cf = self.newconfig()
Georg Brandl8dcaa732010-07-29 12:17:40 +0000975 parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
Georg Brandl96a60ae2010-07-28 13:13:46 +0000976 self.assertEqual(parsed_files, [smbconf])
977 sections = ['global', 'homes', 'printers',
978 'print$', 'pdf-generator', 'tmp', 'Agustin']
979 self.assertEqual(cf.sections(), sections)
980 self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
981 self.assertEqual(cf.getint("global", "max log size"), 50)
982 self.assertEqual(cf.get("global", "hosts allow"), "127.")
983 self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
Fred Drake8ef67672000-09-27 22:45:25 +0000984
Łukasz Langa7f64c8a2010-12-16 01:16:22 +0000985class ConfigParserTestCaseExtendedInterpolation(BasicTestCase):
986 config_class = configparser.ConfigParser
Łukasz Langab6a6f5f2010-12-03 16:28:00 +0000987 interpolation = configparser.ExtendedInterpolation()
988 default_section = 'common'
989
990 def test_extended_interpolation(self):
991 cf = self.fromstring(textwrap.dedent("""
992 [common]
993 favourite Beatle = Paul
994 favourite color = green
995
996 [tom]
997 favourite band = ${favourite color} day
998 favourite pope = John ${favourite Beatle} II
999 sequel = ${favourite pope}I
1000
1001 [ambv]
1002 favourite Beatle = George
1003 son of Edward VII = ${favourite Beatle} V
1004 son of George V = ${son of Edward VII}I
1005
1006 [stanley]
1007 favourite Beatle = ${ambv:favourite Beatle}
1008 favourite pope = ${tom:favourite pope}
1009 favourite color = black
1010 favourite state of mind = paranoid
1011 favourite movie = soylent ${common:favourite color}
1012 favourite song = ${favourite color} sabbath - ${favourite state of mind}
1013 """).strip())
1014
1015 eq = self.assertEqual
1016 eq(cf['common']['favourite Beatle'], 'Paul')
1017 eq(cf['common']['favourite color'], 'green')
1018 eq(cf['tom']['favourite Beatle'], 'Paul')
1019 eq(cf['tom']['favourite color'], 'green')
1020 eq(cf['tom']['favourite band'], 'green day')
1021 eq(cf['tom']['favourite pope'], 'John Paul II')
1022 eq(cf['tom']['sequel'], 'John Paul III')
1023 eq(cf['ambv']['favourite Beatle'], 'George')
1024 eq(cf['ambv']['favourite color'], 'green')
1025 eq(cf['ambv']['son of Edward VII'], 'George V')
1026 eq(cf['ambv']['son of George V'], 'George VI')
1027 eq(cf['stanley']['favourite Beatle'], 'George')
1028 eq(cf['stanley']['favourite color'], 'black')
1029 eq(cf['stanley']['favourite state of mind'], 'paranoid')
1030 eq(cf['stanley']['favourite movie'], 'soylent green')
1031 eq(cf['stanley']['favourite pope'], 'John Paul II')
1032 eq(cf['stanley']['favourite song'],
1033 'black sabbath - paranoid')
1034
1035 def test_endless_loop(self):
1036 cf = self.fromstring(textwrap.dedent("""
1037 [one for you]
1038 ping = ${one for me:pong}
1039
1040 [one for me]
1041 pong = ${one for you:ping}
Łukasz Langa71b37a52010-12-17 21:56:32 +00001042
1043 [selfish]
1044 me = ${me}
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00001045 """).strip())
1046
1047 with self.assertRaises(configparser.InterpolationDepthError):
1048 cf['one for you']['ping']
Łukasz Langa71b37a52010-12-17 21:56:32 +00001049 with self.assertRaises(configparser.InterpolationDepthError):
1050 cf['selfish']['me']
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00001051
Łukasz Langa71b37a52010-12-17 21:56:32 +00001052 def test_strange_options(self):
1053 cf = self.fromstring("""
1054 [dollars]
1055 $var = $$value
1056 $var2 = ${$var}
1057 ${sick} = cannot interpolate me
1058
1059 [interpolated]
1060 $other = ${dollars:$var}
1061 $trying = ${dollars:${sick}}
1062 """)
1063
1064 self.assertEqual(cf['dollars']['$var'], '$value')
1065 self.assertEqual(cf['interpolated']['$other'], '$value')
1066 self.assertEqual(cf['dollars']['${sick}'], 'cannot interpolate me')
1067 exception_class = configparser.InterpolationMissingOptionError
1068 with self.assertRaises(exception_class) as cm:
1069 cf['interpolated']['$trying']
1070 self.assertEqual(cm.exception.reference, 'dollars:${sick')
1071 self.assertEqual(cm.exception.args[2], '}') #rawval
1072
1073
1074 def test_other_errors(self):
1075 cf = self.fromstring("""
1076 [interpolation fail]
1077 case1 = ${where's the brace
1078 case2 = ${does_not_exist}
1079 case3 = ${wrong_section:wrong_value}
1080 case4 = ${i:like:colon:characters}
1081 case5 = $100 for Fail No 5!
1082 """)
1083
1084 with self.assertRaises(configparser.InterpolationSyntaxError):
1085 cf['interpolation fail']['case1']
1086 with self.assertRaises(configparser.InterpolationMissingOptionError):
1087 cf['interpolation fail']['case2']
1088 with self.assertRaises(configparser.InterpolationMissingOptionError):
1089 cf['interpolation fail']['case3']
1090 with self.assertRaises(configparser.InterpolationSyntaxError):
1091 cf['interpolation fail']['case4']
1092 with self.assertRaises(configparser.InterpolationSyntaxError):
1093 cf['interpolation fail']['case5']
1094 with self.assertRaises(ValueError):
1095 cf['interpolation fail']['case6'] = "BLACK $ABBATH"
Łukasz Langab6a6f5f2010-12-03 16:28:00 +00001096
1097
Łukasz Langa7f64c8a2010-12-16 01:16:22 +00001098class ConfigParserTestCaseNoValue(ConfigParserTestCase):
Fred Drake03c44a32010-02-19 06:08:41 +00001099 allow_no_value = True
1100
Łukasz Langa7f64c8a2010-12-16 01:16:22 +00001101class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
1102 config_class = configparser.ConfigParser
Georg Brandl8dcaa732010-07-29 12:17:40 +00001103 delimiters = {'='}
1104 comment_prefixes = {'#'}
1105 allow_no_value = True
1106
1107 def test_cfgparser_dot_3(self):
1108 tricky = support.findfile("cfgparser.3")
1109 cf = self.newconfig()
1110 self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
1111 self.assertEqual(cf.sections(), ['strange',
1112 'corruption',
1113 'yeah, sections can be '
1114 'indented as well',
1115 'another one!',
1116 'no values here',
1117 'tricky interpolation',
1118 'more interpolation'])
Łukasz Langac264c092010-11-20 16:15:37 +00001119 self.assertEqual(cf.getint(self.default_section, 'go',
Fred Drakecc645b92010-09-04 04:35:34 +00001120 vars={'interpolate': '-1'}), -1)
1121 with self.assertRaises(ValueError):
1122 # no interpolation will happen
Łukasz Langac264c092010-11-20 16:15:37 +00001123 cf.getint(self.default_section, 'go', raw=True,
1124 vars={'interpolate': '-1'})
Georg Brandl8dcaa732010-07-29 12:17:40 +00001125 self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
1126 self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
1127 longname = 'yeah, sections can be indented as well'
1128 self.assertFalse(cf.getboolean(longname, 'are they subsections'))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001129 self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
Georg Brandl8dcaa732010-07-29 12:17:40 +00001130 self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
1131 # `go` from DEFAULT
1132 with self.assertRaises(configparser.InterpolationMissingOptionError):
1133 cf.items('no values here')
1134 self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
1135 self.assertEqual(cf.get('tricky interpolation', 'lets'),
1136 cf.get('tricky interpolation', 'go'))
1137 self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
1138
1139 def test_unicode_failure(self):
1140 tricky = support.findfile("cfgparser.3")
1141 cf = self.newconfig()
1142 with self.assertRaises(UnicodeDecodeError):
1143 cf.read(tricky, encoding='ascii')
Fred Drake03c44a32010-02-19 06:08:41 +00001144
Fred Drake88444412010-09-03 04:22:36 +00001145
1146class Issue7005TestCase(unittest.TestCase):
1147 """Test output when None is set() as a value and allow_no_value == False.
1148
1149 http://bugs.python.org/issue7005
1150
1151 """
1152
1153 expected_output = "[section]\noption = None\n\n"
1154
1155 def prepare(self, config_class):
1156 # This is the default, but that's the point.
Łukasz Langa7f64c8a2010-12-16 01:16:22 +00001157 cp = config_class(allow_no_value=False)
Fred Drake88444412010-09-03 04:22:36 +00001158 cp.add_section("section")
1159 cp.set("section", "option", None)
1160 sio = io.StringIO()
1161 cp.write(sio)
1162 return sio.getvalue()
1163
1164 def test_none_as_value_stringified(self):
Łukasz Langa7f64c8a2010-12-16 01:16:22 +00001165 cp = configparser.ConfigParser(allow_no_value=False)
1166 cp.add_section("section")
1167 with self.assertRaises(TypeError):
1168 cp.set("section", "option", None)
Fred Drake88444412010-09-03 04:22:36 +00001169
1170 def test_none_as_value_stringified_raw(self):
1171 output = self.prepare(configparser.RawConfigParser)
1172 self.assertEqual(output, self.expected_output)
1173
1174
Thomas Wouters89f507f2006-12-13 04:49:30 +00001175class SortedTestCase(RawConfigParserTestCase):
Georg Brandl96a60ae2010-07-28 13:13:46 +00001176 dict_type = SortedDict
Thomas Wouters89f507f2006-12-13 04:49:30 +00001177
1178 def test_sorted(self):
Fred Drakea4923622010-08-09 12:52:45 +00001179 cf = self.fromstring("[b]\n"
1180 "o4=1\n"
1181 "o3=2\n"
1182 "o2=3\n"
1183 "o1=4\n"
1184 "[a]\n"
1185 "k=v\n")
Guido van Rossum34d19282007-08-09 01:03:29 +00001186 output = io.StringIO()
Fred Drakea4923622010-08-09 12:52:45 +00001187 cf.write(output)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001188 self.assertEqual(output.getvalue(),
1189 "[a]\n"
1190 "k = v\n\n"
1191 "[b]\n"
1192 "o1 = 4\n"
1193 "o2 = 3\n"
1194 "o3 = 2\n"
1195 "o4 = 1\n\n")
Fred Drake0eebd5c2002-10-25 21:52:00 +00001196
Fred Drake03c44a32010-02-19 06:08:41 +00001197
Georg Brandl96a60ae2010-07-28 13:13:46 +00001198class CompatibleTestCase(CfgParserTestCaseClass):
1199 config_class = configparser.RawConfigParser
Łukasz Langab25a7912010-12-17 01:32:29 +00001200 comment_prefixes = '#;'
1201 inline_comment_prefixes = ';'
Georg Brandl96a60ae2010-07-28 13:13:46 +00001202
1203 def test_comment_handling(self):
1204 config_string = textwrap.dedent("""\
1205 [Commented Bar]
1206 baz=qwe ; a comment
1207 foo: bar # not a comment!
1208 # but this is a comment
1209 ; another comment
Georg Brandl8dcaa732010-07-29 12:17:40 +00001210 quirk: this;is not a comment
Georg Brandl7b280e92010-07-31 20:13:44 +00001211 ; a space must precede an inline comment
Georg Brandl96a60ae2010-07-28 13:13:46 +00001212 """)
1213 cf = self.fromstring(config_string)
Łukasz Langa71b37a52010-12-17 21:56:32 +00001214 self.assertEqual(cf.get('Commented Bar', 'foo'),
1215 'bar # not a comment!')
Georg Brandl96a60ae2010-07-28 13:13:46 +00001216 self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
Łukasz Langa71b37a52010-12-17 21:56:32 +00001217 self.assertEqual(cf.get('Commented Bar', 'quirk'),
1218 'this;is not a comment')
Georg Brandl96a60ae2010-07-28 13:13:46 +00001219
Łukasz Langa71b37a52010-12-17 21:56:32 +00001220class CopyTestCase(BasicTestCase):
1221 config_class = configparser.ConfigParser
1222
1223 def fromstring(self, string, defaults=None):
1224 cf = self.newconfig(defaults)
1225 cf.read_string(string)
1226 cf_copy = self.newconfig()
1227 cf_copy.read_dict(cf)
1228 # we have to clean up option duplicates that appeared because of
1229 # the magic DEFAULTSECT behaviour.
1230 for section in cf_copy.values():
1231 if section.name == self.default_section:
1232 continue
1233 for default, value in cf[self.default_section].items():
1234 if section[default] == value:
1235 del section[default]
1236 return cf_copy
1237
1238class CoverageOneHundredTestCase(unittest.TestCase):
1239 """Covers edge cases in the codebase."""
1240
1241 def test_duplicate_option_error(self):
1242 error = configparser.DuplicateOptionError('section', 'option')
1243 self.assertEqual(error.section, 'section')
1244 self.assertEqual(error.option, 'option')
1245 self.assertEqual(error.source, None)
1246 self.assertEqual(error.lineno, None)
1247 self.assertEqual(error.args, ('section', 'option', None, None))
1248 self.assertEqual(str(error), "Option 'option' in section 'section' "
1249 "already exists")
1250
1251 def test_interpolation_depth_error(self):
1252 error = configparser.InterpolationDepthError('option', 'section',
1253 'rawval')
1254 self.assertEqual(error.args, ('option', 'section', 'rawval'))
1255 self.assertEqual(error.option, 'option')
1256 self.assertEqual(error.section, 'section')
1257
1258 def test_parsing_error(self):
1259 with self.assertRaises(ValueError) as cm:
1260 configparser.ParsingError()
1261 self.assertEqual(str(cm.exception), "Required argument `source' not "
1262 "given.")
1263 with self.assertRaises(ValueError) as cm:
1264 configparser.ParsingError(source='source', filename='filename')
1265 self.assertEqual(str(cm.exception), "Cannot specify both `filename' "
1266 "and `source'. Use `source'.")
1267 error = configparser.ParsingError(filename='source')
1268 self.assertEqual(error.source, 'source')
1269 with warnings.catch_warnings(record=True) as w:
1270 warnings.simplefilter("always", DeprecationWarning)
1271 self.assertEqual(error.filename, 'source')
1272 error.filename = 'filename'
1273 self.assertEqual(error.source, 'filename')
1274 for warning in w:
1275 self.assertTrue(warning.category is DeprecationWarning)
1276
1277 def test_interpolation_validation(self):
1278 parser = configparser.ConfigParser()
1279 parser.read_string("""
1280 [section]
1281 invalid_percent = %
1282 invalid_reference = %(()
1283 invalid_variable = %(does_not_exist)s
1284 """)
1285 with self.assertRaises(configparser.InterpolationSyntaxError) as cm:
1286 parser['section']['invalid_percent']
1287 self.assertEqual(str(cm.exception), "'%' must be followed by '%' or "
1288 "'(', found: '%'")
1289 with self.assertRaises(configparser.InterpolationSyntaxError) as cm:
1290 parser['section']['invalid_reference']
1291 self.assertEqual(str(cm.exception), "bad interpolation variable "
1292 "reference '%(()'")
1293
1294 def test_readfp_deprecation(self):
1295 sio = io.StringIO("""
1296 [section]
1297 option = value
1298 """)
1299 parser = configparser.ConfigParser()
1300 with warnings.catch_warnings(record=True) as w:
1301 warnings.simplefilter("always", DeprecationWarning)
1302 parser.readfp(sio, filename='StringIO')
1303 for warning in w:
1304 self.assertTrue(warning.category is DeprecationWarning)
1305 self.assertEqual(len(parser), 2)
1306 self.assertEqual(parser['section']['option'], 'value')
1307
1308 def test_safeconfigparser_deprecation(self):
1309 with warnings.catch_warnings(record=True) as w:
1310 warnings.simplefilter("always", DeprecationWarning)
1311 parser = configparser.SafeConfigParser()
1312 for warning in w:
1313 self.assertTrue(warning.category is DeprecationWarning)
1314
1315 def test_sectionproxy_repr(self):
1316 parser = configparser.ConfigParser()
1317 parser.read_string("""
1318 [section]
1319 key = value
1320 """)
1321 self.assertEqual(repr(parser['section']), '<Section: section>')
Georg Brandl96a60ae2010-07-28 13:13:46 +00001322
Fred Drakec6f28912002-10-25 19:40:49 +00001323def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001324 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +00001325 ConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001326 ConfigParserTestCaseNonStandardDelimiters,
Łukasz Langa7f64c8a2010-12-16 01:16:22 +00001327 ConfigParserTestCaseNoValue,
1328 ConfigParserTestCaseExtendedInterpolation,
1329 ConfigParserTestCaseLegacyInterpolation,
1330 ConfigParserTestCaseTrickyFile,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001331 MultilineValuesTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001332 RawConfigParserTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001333 RawConfigParserTestCaseNonStandardDelimiters,
1334 RawConfigParserTestSambaConf,
Brian Curtin9a27b0c2010-07-26 00:27:10 +00001335 SortedTestCase,
Fred Drake88444412010-09-03 04:22:36 +00001336 Issue7005TestCase,
Fred Drakea4923622010-08-09 12:52:45 +00001337 StrictTestCase,
Georg Brandl96a60ae2010-07-28 13:13:46 +00001338 CompatibleTestCase,
Łukasz Langa71b37a52010-12-17 21:56:32 +00001339 CopyTestCase,
Łukasz Langac264c092010-11-20 16:15:37 +00001340 ConfigParserTestCaseNonStandardDefaultSection,
Łukasz Langa71b37a52010-12-17 21:56:32 +00001341 CoverageOneHundredTestCase,
Fred Drake03c44a32010-02-19 06:08:41 +00001342 )