Back to index

python3.2  3.2.2
test_cfgparser.py
Go to the documentation of this file.
00001 import collections
00002 import configparser
00003 import io
00004 import os
00005 import sys
00006 import textwrap
00007 import unittest
00008 import warnings
00009 
00010 from test import support
00011 
00012 class SortedDict(collections.UserDict):
00013 
00014     def items(self):
00015         return sorted(self.data.items())
00016 
00017     def keys(self):
00018         return sorted(self.data.keys())
00019 
00020     def values(self):
00021         return [i[1] for i in self.items()]
00022 
00023     def iteritems(self):
00024         return iter(self.items())
00025 
00026     def iterkeys(self):
00027         return iter(self.keys())
00028 
00029     def itervalues(self):
00030         return iter(self.values())
00031 
00032     __iter__ = iterkeys
00033 
00034 
00035 class CfgParserTestCaseClass(unittest.TestCase):
00036     allow_no_value = False
00037     delimiters = ('=', ':')
00038     comment_prefixes = (';', '#')
00039     inline_comment_prefixes = (';', '#')
00040     empty_lines_in_values = True
00041     dict_type = configparser._default_dict
00042     strict = False
00043     default_section = configparser.DEFAULTSECT
00044     interpolation = configparser._UNSET
00045 
00046     def newconfig(self, defaults=None):
00047         arguments = dict(
00048             defaults=defaults,
00049             allow_no_value=self.allow_no_value,
00050             delimiters=self.delimiters,
00051             comment_prefixes=self.comment_prefixes,
00052             inline_comment_prefixes=self.inline_comment_prefixes,
00053             empty_lines_in_values=self.empty_lines_in_values,
00054             dict_type=self.dict_type,
00055             strict=self.strict,
00056             default_section=self.default_section,
00057             interpolation=self.interpolation,
00058         )
00059         instance = self.config_class(**arguments)
00060         return instance
00061 
00062     def fromstring(self, string, defaults=None):
00063         cf = self.newconfig(defaults)
00064         cf.read_string(string)
00065         return cf
00066 
00067 class BasicTestCase(CfgParserTestCaseClass):
00068 
00069     def basic_test(self, cf):
00070         E = ['Commented Bar',
00071              'Foo Bar',
00072              'Internationalized Stuff',
00073              'Long Line',
00074              'Section\\with$weird%characters[\t',
00075              'Spaces',
00076              'Spacey Bar',
00077              'Spacey Bar From The Beginning',
00078              'Types',
00079              ]
00080 
00081         if self.allow_no_value:
00082             E.append('NoValue')
00083         E.sort()
00084         F = [('baz', 'qwe'), ('foo', 'bar3')]
00085 
00086         # API access
00087         L = cf.sections()
00088         L.sort()
00089         eq = self.assertEqual
00090         eq(L, E)
00091         L = cf.items('Spacey Bar From The Beginning')
00092         L.sort()
00093         eq(L, F)
00094 
00095         # mapping access
00096         L = [section for section in cf]
00097         L.sort()
00098         E.append(self.default_section)
00099         E.sort()
00100         eq(L, E)
00101         L = cf['Spacey Bar From The Beginning'].items()
00102         L = sorted(list(L))
00103         eq(L, F)
00104         L = cf.items()
00105         L = sorted(list(L))
00106         self.assertEqual(len(L), len(E))
00107         for name, section in L:
00108             eq(name, section.name)
00109         eq(cf.defaults(), cf[self.default_section])
00110 
00111         # The use of spaces in the section names serves as a
00112         # regression test for SourceForge bug #583248:
00113         # http://www.python.org/sf/583248
00114 
00115         # API access
00116         eq(cf.get('Foo Bar', 'foo'), 'bar1')
00117         eq(cf.get('Spacey Bar', 'foo'), 'bar2')
00118         eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
00119         eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
00120         eq(cf.get('Commented Bar', 'foo'), 'bar4')
00121         eq(cf.get('Commented Bar', 'baz'), 'qwe')
00122         eq(cf.get('Spaces', 'key with spaces'), 'value')
00123         eq(cf.get('Spaces', 'another with spaces'), 'splat!')
00124         eq(cf.getint('Types', 'int'), 42)
00125         eq(cf.get('Types', 'int'), "42")
00126         self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
00127         eq(cf.get('Types', 'float'), "0.44")
00128         eq(cf.getboolean('Types', 'boolean'), False)
00129         eq(cf.get('Types', '123'), 'strange but acceptable')
00130         if self.allow_no_value:
00131             eq(cf.get('NoValue', 'option-without-value'), None)
00132 
00133         # test vars= and fallback=
00134         eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
00135         eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
00136         with self.assertRaises(configparser.NoSectionError):
00137             cf.get('No Such Foo Bar', 'foo')
00138         with self.assertRaises(configparser.NoOptionError):
00139             cf.get('Foo Bar', 'no-such-foo')
00140         eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
00141         eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
00142         eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
00143         eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
00144         eq(cf.getint('Types', 'int', fallback=18), 42)
00145         eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
00146         eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
00147         with self.assertRaises(configparser.NoOptionError):
00148             cf.getint('Types', 'no-such-int')
00149         self.assertAlmostEqual(cf.getfloat('Types', 'float',
00150                                            fallback=0.0), 0.44)
00151         self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
00152                                            fallback=0.0), 0.0)
00153         eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
00154         with self.assertRaises(configparser.NoOptionError):
00155             cf.getfloat('Types', 'no-such-float')
00156         eq(cf.getboolean('Types', 'boolean', fallback=True), False)
00157         eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
00158            "yes") # sic!
00159         eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
00160         with self.assertRaises(configparser.NoOptionError):
00161             cf.getboolean('Types', 'no-such-boolean')
00162         eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
00163         if self.allow_no_value:
00164             eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
00165             eq(cf.get('NoValue', 'no-such-option-without-value',
00166                       fallback=False), False)
00167 
00168         # mapping access
00169         eq(cf['Foo Bar']['foo'], 'bar1')
00170         eq(cf['Spacey Bar']['foo'], 'bar2')
00171         section = cf['Spacey Bar From The Beginning']
00172         eq(section.name, 'Spacey Bar From The Beginning')
00173         self.assertIs(section.parser, cf)
00174         with self.assertRaises(AttributeError):
00175             section.name = 'Name is read-only'
00176         with self.assertRaises(AttributeError):
00177             section.parser = 'Parser is read-only'
00178         eq(section['foo'], 'bar3')
00179         eq(section['baz'], 'qwe')
00180         eq(cf['Commented Bar']['foo'], 'bar4')
00181         eq(cf['Commented Bar']['baz'], 'qwe')
00182         eq(cf['Spaces']['key with spaces'], 'value')
00183         eq(cf['Spaces']['another with spaces'], 'splat!')
00184         eq(cf['Long Line']['foo'],
00185            'this line is much, much longer than my editor\nlikes it.')
00186         if self.allow_no_value:
00187             eq(cf['NoValue']['option-without-value'], None)
00188         # test vars= and fallback=
00189         eq(cf['Foo Bar'].get('foo', 'baz'), 'bar1')
00190         eq(cf['Foo Bar'].get('foo', fallback='baz'), 'bar1')
00191         eq(cf['Foo Bar'].get('foo', vars={'foo': 'baz'}), 'baz')
00192         with self.assertRaises(KeyError):
00193             cf['No Such Foo Bar']['foo']
00194         with self.assertRaises(KeyError):
00195             cf['Foo Bar']['no-such-foo']
00196         with self.assertRaises(KeyError):
00197             cf['No Such Foo Bar'].get('foo', fallback='baz')
00198         eq(cf['Foo Bar'].get('no-such-foo', 'baz'), 'baz')
00199         eq(cf['Foo Bar'].get('no-such-foo', fallback='baz'), 'baz')
00200         eq(cf['Foo Bar'].get('no-such-foo'), None)
00201         eq(cf['Spacey Bar'].get('foo', None), 'bar2')
00202         eq(cf['Spacey Bar'].get('foo', fallback=None), 'bar2')
00203         with self.assertRaises(KeyError):
00204             cf['No Such Spacey Bar'].get('foo', None)
00205         eq(cf['Types'].getint('int', 18), 42)
00206         eq(cf['Types'].getint('int', fallback=18), 42)
00207         eq(cf['Types'].getint('no-such-int', 18), 18)
00208         eq(cf['Types'].getint('no-such-int', fallback=18), 18)
00209         eq(cf['Types'].getint('no-such-int', "18"), "18") # sic!
00210         eq(cf['Types'].getint('no-such-int', fallback="18"), "18") # sic!
00211         eq(cf['Types'].getint('no-such-int'), None)
00212         self.assertAlmostEqual(cf['Types'].getfloat('float', 0.0), 0.44)
00213         self.assertAlmostEqual(cf['Types'].getfloat('float',
00214                                                     fallback=0.0), 0.44)
00215         self.assertAlmostEqual(cf['Types'].getfloat('no-such-float', 0.0), 0.0)
00216         self.assertAlmostEqual(cf['Types'].getfloat('no-such-float',
00217                                                     fallback=0.0), 0.0)
00218         eq(cf['Types'].getfloat('no-such-float', "0.0"), "0.0") # sic!
00219         eq(cf['Types'].getfloat('no-such-float', fallback="0.0"), "0.0") # sic!
00220         eq(cf['Types'].getfloat('no-such-float'), None)
00221         eq(cf['Types'].getboolean('boolean', True), False)
00222         eq(cf['Types'].getboolean('boolean', fallback=True), False)
00223         eq(cf['Types'].getboolean('no-such-boolean', "yes"), "yes") # sic!
00224         eq(cf['Types'].getboolean('no-such-boolean', fallback="yes"),
00225            "yes") # sic!
00226         eq(cf['Types'].getboolean('no-such-boolean', True), True)
00227         eq(cf['Types'].getboolean('no-such-boolean', fallback=True), True)
00228         eq(cf['Types'].getboolean('no-such-boolean'), None)
00229         if self.allow_no_value:
00230             eq(cf['NoValue'].get('option-without-value', False), None)
00231             eq(cf['NoValue'].get('option-without-value', fallback=False), None)
00232             eq(cf['NoValue'].get('no-such-option-without-value', False), False)
00233             eq(cf['NoValue'].get('no-such-option-without-value',
00234                       fallback=False), False)
00235 
00236         # Make sure the right things happen for remove_section() and
00237         # remove_option(); added to include check for SourceForge bug #123324.
00238 
00239         cf[self.default_section]['this_value'] = '1'
00240         cf[self.default_section]['that_value'] = '2'
00241 
00242         # API access
00243         self.assertTrue(cf.remove_section('Spaces'))
00244         self.assertFalse(cf.has_option('Spaces', 'key with spaces'))
00245         self.assertFalse(cf.remove_section('Spaces'))
00246         self.assertFalse(cf.remove_section(self.default_section))
00247         self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
00248                         "remove_option() failed to report existence of option")
00249         self.assertFalse(cf.has_option('Foo Bar', 'foo'),
00250                     "remove_option() failed to remove option")
00251         self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
00252                     "remove_option() failed to report non-existence of option"
00253                     " that was removed")
00254         self.assertTrue(cf.has_option('Foo Bar', 'this_value'))
00255         self.assertFalse(cf.remove_option('Foo Bar', 'this_value'))
00256         self.assertTrue(cf.remove_option(self.default_section, 'this_value'))
00257         self.assertFalse(cf.has_option('Foo Bar', 'this_value'))
00258         self.assertFalse(cf.remove_option(self.default_section, 'this_value'))
00259 
00260         with self.assertRaises(configparser.NoSectionError) as cm:
00261             cf.remove_option('No Such Section', 'foo')
00262         self.assertEqual(cm.exception.args, ('No Such Section',))
00263 
00264         eq(cf.get('Long Line', 'foo'),
00265            'this line is much, much longer than my editor\nlikes it.')
00266 
00267         # mapping access
00268         del cf['Types']
00269         self.assertFalse('Types' in cf)
00270         with self.assertRaises(KeyError):
00271             del cf['Types']
00272         with self.assertRaises(ValueError):
00273             del cf[self.default_section]
00274         del cf['Spacey Bar']['foo']
00275         self.assertFalse('foo' in cf['Spacey Bar'])
00276         with self.assertRaises(KeyError):
00277             del cf['Spacey Bar']['foo']
00278         self.assertTrue('that_value' in cf['Spacey Bar'])
00279         with self.assertRaises(KeyError):
00280             del cf['Spacey Bar']['that_value']
00281         del cf[self.default_section]['that_value']
00282         self.assertFalse('that_value' in cf['Spacey Bar'])
00283         with self.assertRaises(KeyError):
00284             del cf[self.default_section]['that_value']
00285         with self.assertRaises(KeyError):
00286             del cf['No Such Section']['foo']
00287 
00288         # Don't add new asserts below in this method as most of the options
00289         # and sections are now removed.
00290 
00291     def test_basic(self):
00292         config_string = """\
00293 [Foo Bar]
00294 foo{0[0]}bar1
00295 [Spacey Bar]
00296 foo {0[0]} bar2
00297 [Spacey Bar From The Beginning]
00298   foo {0[0]} bar3
00299   baz {0[0]} qwe
00300 [Commented Bar]
00301 foo{0[1]} bar4 {1[1]} comment
00302 baz{0[0]}qwe {1[0]}another one
00303 [Long Line]
00304 foo{0[1]} this line is much, much longer than my editor
00305    likes it.
00306 [Section\\with$weird%characters[\t]
00307 [Internationalized Stuff]
00308 foo[bg]{0[1]} Bulgarian
00309 foo{0[0]}Default
00310 foo[en]{0[0]}English
00311 foo[de]{0[0]}Deutsch
00312 [Spaces]
00313 key with spaces {0[1]} value
00314 another with spaces {0[0]} splat!
00315 [Types]
00316 int {0[1]} 42
00317 float {0[0]} 0.44
00318 boolean {0[0]} NO
00319 123 {0[1]} strange but acceptable
00320 """.format(self.delimiters, self.comment_prefixes)
00321         if self.allow_no_value:
00322             config_string += (
00323                 "[NoValue]\n"
00324                 "option-without-value\n"
00325                 )
00326         cf = self.fromstring(config_string)
00327         self.basic_test(cf)
00328         if self.strict:
00329             with self.assertRaises(configparser.DuplicateOptionError):
00330                 cf.read_string(textwrap.dedent("""\
00331                     [Duplicate Options Here]
00332                     option {0[0]} with a value
00333                     option {0[1]} with another value
00334                 """.format(self.delimiters)))
00335             with self.assertRaises(configparser.DuplicateSectionError):
00336                 cf.read_string(textwrap.dedent("""\
00337                     [And Now For Something]
00338                     completely different {0[0]} True
00339                     [And Now For Something]
00340                     the larch {0[1]} 1
00341                 """.format(self.delimiters)))
00342         else:
00343             cf.read_string(textwrap.dedent("""\
00344                 [Duplicate Options Here]
00345                 option {0[0]} with a value
00346                 option {0[1]} with another value
00347             """.format(self.delimiters)))
00348 
00349             cf.read_string(textwrap.dedent("""\
00350                 [And Now For Something]
00351                 completely different {0[0]} True
00352                 [And Now For Something]
00353                 the larch {0[1]} 1
00354             """.format(self.delimiters)))
00355 
00356     def test_basic_from_dict(self):
00357         config = {
00358             "Foo Bar": {
00359                 "foo": "bar1",
00360             },
00361             "Spacey Bar": {
00362                 "foo": "bar2",
00363             },
00364             "Spacey Bar From The Beginning": {
00365                 "foo": "bar3",
00366                 "baz": "qwe",
00367             },
00368             "Commented Bar": {
00369                 "foo": "bar4",
00370                 "baz": "qwe",
00371             },
00372             "Long Line": {
00373                 "foo": "this line is much, much longer than my editor\nlikes "
00374                        "it.",
00375             },
00376             "Section\\with$weird%characters[\t": {
00377             },
00378             "Internationalized Stuff": {
00379                 "foo[bg]": "Bulgarian",
00380                 "foo": "Default",
00381                 "foo[en]": "English",
00382                 "foo[de]": "Deutsch",
00383             },
00384             "Spaces": {
00385                 "key with spaces": "value",
00386                 "another with spaces": "splat!",
00387             },
00388             "Types": {
00389                 "int": 42,
00390                 "float": 0.44,
00391                 "boolean": False,
00392                 123: "strange but acceptable",
00393             },
00394         }
00395         if self.allow_no_value:
00396             config.update({
00397                 "NoValue": {
00398                     "option-without-value": None,
00399                 }
00400             })
00401         cf = self.newconfig()
00402         cf.read_dict(config)
00403         self.basic_test(cf)
00404         if self.strict:
00405             with self.assertRaises(configparser.DuplicateSectionError):
00406                 cf.read_dict({
00407                     '1': {'key': 'value'},
00408                     1: {'key2': 'value2'},
00409                 })
00410             with self.assertRaises(configparser.DuplicateOptionError):
00411                 cf.read_dict({
00412                     "Duplicate Options Here": {
00413                         'option': 'with a value',
00414                         'OPTION': 'with another value',
00415                     },
00416                 })
00417         else:
00418             cf.read_dict({
00419                 'section': {'key': 'value'},
00420                 'SECTION': {'key2': 'value2'},
00421             })
00422             cf.read_dict({
00423                 "Duplicate Options Here": {
00424                     'option': 'with a value',
00425                     'OPTION': 'with another value',
00426                 },
00427             })
00428 
00429     def test_case_sensitivity(self):
00430         cf = self.newconfig()
00431         cf.add_section("A")
00432         cf.add_section("a")
00433         cf.add_section("B")
00434         L = cf.sections()
00435         L.sort()
00436         eq = self.assertEqual
00437         eq(L, ["A", "B", "a"])
00438         cf.set("a", "B", "value")
00439         eq(cf.options("a"), ["b"])
00440         eq(cf.get("a", "b"), "value",
00441            "could not locate option, expecting case-insensitive option names")
00442         with self.assertRaises(configparser.NoSectionError):
00443             # section names are case-sensitive
00444             cf.set("b", "A", "value")
00445         self.assertTrue(cf.has_option("a", "b"))
00446         self.assertFalse(cf.has_option("b", "b"))
00447         cf.set("A", "A-B", "A-B value")
00448         for opt in ("a-b", "A-b", "a-B", "A-B"):
00449             self.assertTrue(
00450                 cf.has_option("A", opt),
00451                 "has_option() returned false for option which should exist")
00452         eq(cf.options("A"), ["a-b"])
00453         eq(cf.options("a"), ["b"])
00454         cf.remove_option("a", "B")
00455         eq(cf.options("a"), [])
00456 
00457         # SF bug #432369:
00458         cf = self.fromstring(
00459             "[MySection]\nOption{} first line   \n\tsecond line   \n".format(
00460                 self.delimiters[0]))
00461         eq(cf.options("MySection"), ["option"])
00462         eq(cf.get("MySection", "Option"), "first line\nsecond line")
00463 
00464         # SF bug #561822:
00465         cf = self.fromstring("[section]\n"
00466                              "nekey{}nevalue\n".format(self.delimiters[0]),
00467                              defaults={"key":"value"})
00468         self.assertTrue(cf.has_option("section", "Key"))
00469 
00470 
00471     def test_case_sensitivity_mapping_access(self):
00472         cf = self.newconfig()
00473         cf["A"] = {}
00474         cf["a"] = {"B": "value"}
00475         cf["B"] = {}
00476         L = [section for section in cf]
00477         L.sort()
00478         eq = self.assertEqual
00479         elem_eq = self.assertCountEqual
00480         eq(L, sorted(["A", "B", self.default_section, "a"]))
00481         eq(cf["a"].keys(), {"b"})
00482         eq(cf["a"]["b"], "value",
00483            "could not locate option, expecting case-insensitive option names")
00484         with self.assertRaises(KeyError):
00485             # section names are case-sensitive
00486             cf["b"]["A"] = "value"
00487         self.assertTrue("b" in cf["a"])
00488         cf["A"]["A-B"] = "A-B value"
00489         for opt in ("a-b", "A-b", "a-B", "A-B"):
00490             self.assertTrue(
00491                 opt in cf["A"],
00492                 "has_option() returned false for option which should exist")
00493         eq(cf["A"].keys(), {"a-b"})
00494         eq(cf["a"].keys(), {"b"})
00495         del cf["a"]["B"]
00496         elem_eq(cf["a"].keys(), {})
00497 
00498         # SF bug #432369:
00499         cf = self.fromstring(
00500             "[MySection]\nOption{} first line   \n\tsecond line   \n".format(
00501                 self.delimiters[0]))
00502         eq(cf["MySection"].keys(), {"option"})
00503         eq(cf["MySection"]["Option"], "first line\nsecond line")
00504 
00505         # SF bug #561822:
00506         cf = self.fromstring("[section]\n"
00507                              "nekey{}nevalue\n".format(self.delimiters[0]),
00508                              defaults={"key":"value"})
00509         self.assertTrue("Key" in cf["section"])
00510 
00511     def test_default_case_sensitivity(self):
00512         cf = self.newconfig({"foo": "Bar"})
00513         self.assertEqual(
00514             cf.get(self.default_section, "Foo"), "Bar",
00515             "could not locate option, expecting case-insensitive option names")
00516         cf = self.newconfig({"Foo": "Bar"})
00517         self.assertEqual(
00518             cf.get(self.default_section, "Foo"), "Bar",
00519             "could not locate option, expecting case-insensitive defaults")
00520 
00521     def test_parse_errors(self):
00522         cf = self.newconfig()
00523         self.parse_error(cf, configparser.ParsingError,
00524                          "[Foo]\n"
00525                          "{}val-without-opt-name\n".format(self.delimiters[0]))
00526         self.parse_error(cf, configparser.ParsingError,
00527                          "[Foo]\n"
00528                          "{}val-without-opt-name\n".format(self.delimiters[1]))
00529         e = self.parse_error(cf, configparser.MissingSectionHeaderError,
00530                              "No Section!\n")
00531         self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
00532         if not self.allow_no_value:
00533             e = self.parse_error(cf, configparser.ParsingError,
00534                                 "[Foo]\n  wrong-indent\n")
00535             self.assertEqual(e.args, ('<???>',))
00536             # read_file on a real file
00537             tricky = support.findfile("cfgparser.3")
00538             if self.delimiters[0] == '=':
00539                 error = configparser.ParsingError
00540                 expected = (tricky,)
00541             else:
00542                 error = configparser.MissingSectionHeaderError
00543                 expected = (tricky, 1,
00544                             '  # INI with as many tricky parts as possible\n')
00545             with open(tricky, encoding='utf-8') as f:
00546                 e = self.parse_error(cf, error, f)
00547             self.assertEqual(e.args, expected)
00548 
00549     def parse_error(self, cf, exc, src):
00550         if hasattr(src, 'readline'):
00551             sio = src
00552         else:
00553             sio = io.StringIO(src)
00554         with self.assertRaises(exc) as cm:
00555             cf.read_file(sio)
00556         return cm.exception
00557 
00558     def test_query_errors(self):
00559         cf = self.newconfig()
00560         self.assertEqual(cf.sections(), [],
00561                          "new ConfigParser should have no defined sections")
00562         self.assertFalse(cf.has_section("Foo"),
00563                          "new ConfigParser should have no acknowledged "
00564                          "sections")
00565         with self.assertRaises(configparser.NoSectionError):
00566             cf.options("Foo")
00567         with self.assertRaises(configparser.NoSectionError):
00568             cf.set("foo", "bar", "value")
00569         e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
00570         self.assertEqual(e.args, ("foo",))
00571         cf.add_section("foo")
00572         e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
00573         self.assertEqual(e.args, ("bar", "foo"))
00574 
00575     def get_error(self, cf, exc, section, option):
00576         try:
00577             cf.get(section, option)
00578         except exc as e:
00579             return e
00580         else:
00581             self.fail("expected exception type %s.%s"
00582                       % (exc.__module__, exc.__name__))
00583 
00584     def test_boolean(self):
00585         cf = self.fromstring(
00586             "[BOOLTEST]\n"
00587             "T1{equals}1\n"
00588             "T2{equals}TRUE\n"
00589             "T3{equals}True\n"
00590             "T4{equals}oN\n"
00591             "T5{equals}yes\n"
00592             "F1{equals}0\n"
00593             "F2{equals}FALSE\n"
00594             "F3{equals}False\n"
00595             "F4{equals}oFF\n"
00596             "F5{equals}nO\n"
00597             "E1{equals}2\n"
00598             "E2{equals}foo\n"
00599             "E3{equals}-1\n"
00600             "E4{equals}0.1\n"
00601             "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
00602             )
00603         for x in range(1, 5):
00604             self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
00605             self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
00606             self.assertRaises(ValueError,
00607                               cf.getboolean, 'BOOLTEST', 'e%d' % x)
00608 
00609     def test_weird_errors(self):
00610         cf = self.newconfig()
00611         cf.add_section("Foo")
00612         with self.assertRaises(configparser.DuplicateSectionError) as cm:
00613             cf.add_section("Foo")
00614         e = cm.exception
00615         self.assertEqual(str(e), "Section 'Foo' already exists")
00616         self.assertEqual(e.args, ("Foo", None, None))
00617 
00618         if self.strict:
00619             with self.assertRaises(configparser.DuplicateSectionError) as cm:
00620                 cf.read_string(textwrap.dedent("""\
00621                     [Foo]
00622                     will this be added{equals}True
00623                     [Bar]
00624                     what about this{equals}True
00625                     [Foo]
00626                     oops{equals}this won't
00627                 """.format(equals=self.delimiters[0])), source='<foo-bar>')
00628             e = cm.exception
00629             self.assertEqual(str(e), "While reading from <foo-bar> [line  5]: "
00630                                      "section 'Foo' already exists")
00631             self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
00632 
00633             with self.assertRaises(configparser.DuplicateOptionError) as cm:
00634                 cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
00635             e = cm.exception
00636             self.assertEqual(str(e), "While reading from <dict>: option 'opt' "
00637                                      "in section 'Bar' already exists")
00638             self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
00639 
00640     def test_write(self):
00641         config_string = (
00642             "[Long Line]\n"
00643             "foo{0[0]} this line is much, much longer than my editor\n"
00644             "   likes it.\n"
00645             "[{default_section}]\n"
00646             "foo{0[1]} another very\n"
00647             " long line\n"
00648             "[Long Line - With Comments!]\n"
00649             "test {0[1]} we        {comment} can\n"
00650             "            also      {comment} place\n"
00651             "            comments  {comment} in\n"
00652             "            multiline {comment} values"
00653             "\n".format(self.delimiters, comment=self.comment_prefixes[0],
00654                         default_section=self.default_section)
00655             )
00656         if self.allow_no_value:
00657             config_string += (
00658             "[Valueless]\n"
00659             "option-without-value\n"
00660             )
00661 
00662         cf = self.fromstring(config_string)
00663         for space_around_delimiters in (True, False):
00664             output = io.StringIO()
00665             cf.write(output, space_around_delimiters=space_around_delimiters)
00666             delimiter = self.delimiters[0]
00667             if space_around_delimiters:
00668                 delimiter = " {} ".format(delimiter)
00669             expect_string = (
00670                 "[{default_section}]\n"
00671                 "foo{equals}another very\n"
00672                 "\tlong line\n"
00673                 "\n"
00674                 "[Long Line]\n"
00675                 "foo{equals}this line is much, much longer than my editor\n"
00676                 "\tlikes it.\n"
00677                 "\n"
00678                 "[Long Line - With Comments!]\n"
00679                 "test{equals}we\n"
00680                 "\talso\n"
00681                 "\tcomments\n"
00682                 "\tmultiline\n"
00683                 "\n".format(equals=delimiter,
00684                             default_section=self.default_section)
00685                 )
00686             if self.allow_no_value:
00687                 expect_string += (
00688                     "[Valueless]\n"
00689                     "option-without-value\n"
00690                     "\n"
00691                     )
00692             self.assertEqual(output.getvalue(), expect_string)
00693 
00694     def test_set_string_types(self):
00695         cf = self.fromstring("[sect]\n"
00696                              "option1{eq}foo\n".format(eq=self.delimiters[0]))
00697         # Check that we don't get an exception when setting values in
00698         # an existing section using strings:
00699         class mystr(str):
00700             pass
00701         cf.set("sect", "option1", "splat")
00702         cf.set("sect", "option1", mystr("splat"))
00703         cf.set("sect", "option2", "splat")
00704         cf.set("sect", "option2", mystr("splat"))
00705         cf.set("sect", "option1", "splat")
00706         cf.set("sect", "option2", "splat")
00707 
00708     def test_read_returns_file_list(self):
00709         if self.delimiters[0] != '=':
00710             # skip reading the file if we're using an incompatible format
00711             return
00712         file1 = support.findfile("cfgparser.1")
00713         # check when we pass a mix of readable and non-readable files:
00714         cf = self.newconfig()
00715         parsed_files = cf.read([file1, "nonexistent-file"])
00716         self.assertEqual(parsed_files, [file1])
00717         self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
00718         # check when we pass only a filename:
00719         cf = self.newconfig()
00720         parsed_files = cf.read(file1)
00721         self.assertEqual(parsed_files, [file1])
00722         self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
00723         # check when we pass only missing files:
00724         cf = self.newconfig()
00725         parsed_files = cf.read(["nonexistent-file"])
00726         self.assertEqual(parsed_files, [])
00727         # check when we pass no files:
00728         cf = self.newconfig()
00729         parsed_files = cf.read([])
00730         self.assertEqual(parsed_files, [])
00731 
00732     # shared by subclasses
00733     def get_interpolation_config(self):
00734         return self.fromstring(
00735             "[Foo]\n"
00736             "bar{equals}something %(with1)s interpolation (1 step)\n"
00737             "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
00738             "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
00739             "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
00740             "with11{equals}%(with10)s\n"
00741             "with10{equals}%(with9)s\n"
00742             "with9{equals}%(with8)s\n"
00743             "with8{equals}%(With7)s\n"
00744             "with7{equals}%(WITH6)s\n"
00745             "with6{equals}%(with5)s\n"
00746             "With5{equals}%(with4)s\n"
00747             "WITH4{equals}%(with3)s\n"
00748             "with3{equals}%(with2)s\n"
00749             "with2{equals}%(with1)s\n"
00750             "with1{equals}with\n"
00751             "\n"
00752             "[Mutual Recursion]\n"
00753             "foo{equals}%(bar)s\n"
00754             "bar{equals}%(foo)s\n"
00755             "\n"
00756             "[Interpolation Error]\n"
00757             # no definition for 'reference'
00758             "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
00759 
00760     def check_items_config(self, expected):
00761         cf = self.fromstring("""
00762             [section]
00763             name {0[0]} %(value)s
00764             key{0[1]} |%(name)s|
00765             getdefault{0[1]} |%(default)s|
00766         """.format(self.delimiters), defaults={"default": "<default>"})
00767         L = list(cf.items("section", vars={'value': 'value'}))
00768         L.sort()
00769         self.assertEqual(L, expected)
00770         with self.assertRaises(configparser.NoSectionError):
00771             cf.items("no such section")
00772 
00773 
00774 class StrictTestCase(BasicTestCase):
00775     config_class = configparser.RawConfigParser
00776     strict = True
00777 
00778 
00779 class ConfigParserTestCase(BasicTestCase):
00780     config_class = configparser.ConfigParser
00781 
00782     def test_interpolation(self):
00783         cf = self.get_interpolation_config()
00784         eq = self.assertEqual
00785         eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
00786         eq(cf.get("Foo", "bar9"),
00787            "something with lots of interpolation (9 steps)")
00788         eq(cf.get("Foo", "bar10"),
00789            "something with lots of interpolation (10 steps)")
00790         e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
00791         if self.interpolation == configparser._UNSET:
00792             self.assertEqual(e.args, ("bar11", "Foo", "%(with1)s"))
00793         elif isinstance(self.interpolation, configparser.LegacyInterpolation):
00794             self.assertEqual(e.args, ("bar11", "Foo",
00795                 "something %(with11)s lots of interpolation (11 steps)"))
00796 
00797     def test_interpolation_missing_value(self):
00798         cf = self.get_interpolation_config()
00799         e = self.get_error(cf, configparser.InterpolationMissingOptionError,
00800                            "Interpolation Error", "name")
00801         self.assertEqual(e.reference, "reference")
00802         self.assertEqual(e.section, "Interpolation Error")
00803         self.assertEqual(e.option, "name")
00804         if self.interpolation == configparser._UNSET:
00805             self.assertEqual(e.args, ('name', 'Interpolation Error',
00806                                     '', 'reference'))
00807         elif isinstance(self.interpolation, configparser.LegacyInterpolation):
00808             self.assertEqual(e.args, ('name', 'Interpolation Error',
00809                                     '%(reference)s', 'reference'))
00810 
00811     def test_items(self):
00812         self.check_items_config([('default', '<default>'),
00813                                  ('getdefault', '|<default>|'),
00814                                  ('key', '|value|'),
00815                                  ('name', 'value'),
00816                                  ('value', 'value')])
00817 
00818     def test_safe_interpolation(self):
00819         # See http://www.python.org/sf/511737
00820         cf = self.fromstring("[section]\n"
00821                              "option1{eq}xxx\n"
00822                              "option2{eq}%(option1)s/xxx\n"
00823                              "ok{eq}%(option1)s/%%s\n"
00824                              "not_ok{eq}%(option2)s/%%s".format(
00825                                  eq=self.delimiters[0]))
00826         self.assertEqual(cf.get("section", "ok"), "xxx/%s")
00827         if self.interpolation == configparser._UNSET:
00828             self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
00829         elif isinstance(self.interpolation, configparser.LegacyInterpolation):
00830             with self.assertRaises(TypeError):
00831                 cf.get("section", "not_ok")
00832 
00833     def test_set_malformatted_interpolation(self):
00834         cf = self.fromstring("[sect]\n"
00835                              "option1{eq}foo\n".format(eq=self.delimiters[0]))
00836 
00837         self.assertEqual(cf.get('sect', "option1"), "foo")
00838 
00839         self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
00840         self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
00841         self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
00842 
00843         self.assertEqual(cf.get('sect', "option1"), "foo")
00844 
00845         # bug #5741: double percents are *not* malformed
00846         cf.set("sect", "option2", "foo%%bar")
00847         self.assertEqual(cf.get("sect", "option2"), "foo%bar")
00848 
00849     def test_set_nonstring_types(self):
00850         cf = self.fromstring("[sect]\n"
00851                              "option1{eq}foo\n".format(eq=self.delimiters[0]))
00852         # Check that we get a TypeError when setting non-string values
00853         # in an existing section:
00854         self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
00855         self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
00856         self.assertRaises(TypeError, cf.set, "sect", "option1", object())
00857         self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
00858         self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
00859         self.assertRaises(TypeError, cf.set, "sect", "option2", object())
00860         self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
00861         self.assertRaises(TypeError, cf.add_section, 123)
00862 
00863     def test_add_section_default(self):
00864         cf = self.newconfig()
00865         self.assertRaises(ValueError, cf.add_section, self.default_section)
00866 
00867 
00868 class ConfigParserTestCaseNoInterpolation(BasicTestCase):
00869     config_class = configparser.ConfigParser
00870     interpolation = None
00871     ini = textwrap.dedent("""
00872         [numbers]
00873         one = 1
00874         two = %(one)s * 2
00875         three = ${common:one} * 3
00876 
00877         [hexen]
00878         sixteen = ${numbers:two} * 8
00879     """).strip()
00880 
00881     def assertMatchesIni(self, cf):
00882         self.assertEqual(cf['numbers']['one'], '1')
00883         self.assertEqual(cf['numbers']['two'], '%(one)s * 2')
00884         self.assertEqual(cf['numbers']['three'], '${common:one} * 3')
00885         self.assertEqual(cf['hexen']['sixteen'], '${numbers:two} * 8')
00886 
00887     def test_no_interpolation(self):
00888         cf = self.fromstring(self.ini)
00889         self.assertMatchesIni(cf)
00890 
00891     def test_empty_case(self):
00892         cf = self.newconfig()
00893         self.assertIsNone(cf.read_string(""))
00894 
00895     def test_none_as_default_interpolation(self):
00896         class CustomConfigParser(configparser.ConfigParser):
00897             _DEFAULT_INTERPOLATION = None
00898 
00899         cf = CustomConfigParser()
00900         cf.read_string(self.ini)
00901         self.assertMatchesIni(cf)
00902 
00903 
00904 class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase):
00905     config_class = configparser.ConfigParser
00906     interpolation = configparser.LegacyInterpolation()
00907 
00908     def test_set_malformatted_interpolation(self):
00909         cf = self.fromstring("[sect]\n"
00910                              "option1{eq}foo\n".format(eq=self.delimiters[0]))
00911 
00912         self.assertEqual(cf.get('sect', "option1"), "foo")
00913 
00914         cf.set("sect", "option1", "%foo")
00915         self.assertEqual(cf.get('sect', "option1"), "%foo")
00916         cf.set("sect", "option1", "foo%")
00917         self.assertEqual(cf.get('sect', "option1"), "foo%")
00918         cf.set("sect", "option1", "f%oo")
00919         self.assertEqual(cf.get('sect', "option1"), "f%oo")
00920 
00921         # bug #5741: double percents are *not* malformed
00922         cf.set("sect", "option2", "foo%%bar")
00923         self.assertEqual(cf.get("sect", "option2"), "foo%%bar")
00924 
00925 class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
00926     delimiters = (':=', '$')
00927     comment_prefixes = ('//', '"')
00928     inline_comment_prefixes = ('//', '"')
00929 
00930 class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
00931     default_section = 'general'
00932 
00933 class MultilineValuesTestCase(BasicTestCase):
00934     config_class = configparser.ConfigParser
00935     wonderful_spam = ("I'm having spam spam spam spam "
00936                       "spam spam spam beaked beans spam "
00937                       "spam spam and spam!").replace(' ', '\t\n')
00938 
00939     def setUp(self):
00940         cf = self.newconfig()
00941         for i in range(100):
00942             s = 'section{}'.format(i)
00943             cf.add_section(s)
00944             for j in range(10):
00945                 cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
00946         with open(support.TESTFN, 'w') as f:
00947             cf.write(f)
00948 
00949     def tearDown(self):
00950         os.unlink(support.TESTFN)
00951 
00952     def test_dominating_multiline_values(self):
00953         # We're reading from file because this is where the code changed
00954         # during performance updates in Python 3.2
00955         cf_from_file = self.newconfig()
00956         with open(support.TESTFN) as f:
00957             cf_from_file.read_file(f)
00958         self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
00959                          self.wonderful_spam.replace('\t\n', '\n'))
00960 
00961 class RawConfigParserTestCase(BasicTestCase):
00962     config_class = configparser.RawConfigParser
00963 
00964     def test_interpolation(self):
00965         cf = self.get_interpolation_config()
00966         eq = self.assertEqual
00967         eq(cf.get("Foo", "bar"),
00968            "something %(with1)s interpolation (1 step)")
00969         eq(cf.get("Foo", "bar9"),
00970            "something %(with9)s lots of interpolation (9 steps)")
00971         eq(cf.get("Foo", "bar10"),
00972            "something %(with10)s lots of interpolation (10 steps)")
00973         eq(cf.get("Foo", "bar11"),
00974            "something %(with11)s lots of interpolation (11 steps)")
00975 
00976     def test_items(self):
00977         self.check_items_config([('default', '<default>'),
00978                                  ('getdefault', '|%(default)s|'),
00979                                  ('key', '|%(name)s|'),
00980                                  ('name', '%(value)s'),
00981                                  ('value', 'value')])
00982 
00983     def test_set_nonstring_types(self):
00984         cf = self.newconfig()
00985         cf.add_section('non-string')
00986         cf.set('non-string', 'int', 1)
00987         cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
00988         cf.set('non-string', 'dict', {'pi': 3.14159})
00989         self.assertEqual(cf.get('non-string', 'int'), 1)
00990         self.assertEqual(cf.get('non-string', 'list'),
00991                          [0, 1, 1, 2, 3, 5, 8, 13])
00992         self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
00993         cf.add_section(123)
00994         cf.set(123, 'this is sick', True)
00995         self.assertEqual(cf.get(123, 'this is sick'), True)
00996         if cf._dict is configparser._default_dict:
00997             # would not work for SortedDict; only checking for the most common
00998             # default dictionary (OrderedDict)
00999             cf.optionxform = lambda x: x
01000             cf.set('non-string', 1, 1)
01001             self.assertEqual(cf.get('non-string', 1), 1)
01002 
01003 class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
01004     delimiters = (':=', '$')
01005     comment_prefixes = ('//', '"')
01006     inline_comment_prefixes = ('//', '"')
01007 
01008 class RawConfigParserTestSambaConf(CfgParserTestCaseClass):
01009     config_class = configparser.RawConfigParser
01010     comment_prefixes = ('#', ';', '----')
01011     inline_comment_prefixes = ('//',)
01012     empty_lines_in_values = False
01013 
01014     def test_reading(self):
01015         smbconf = support.findfile("cfgparser.2")
01016         # check when we pass a mix of readable and non-readable files:
01017         cf = self.newconfig()
01018         parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
01019         self.assertEqual(parsed_files, [smbconf])
01020         sections = ['global', 'homes', 'printers',
01021                     'print$', 'pdf-generator', 'tmp', 'Agustin']
01022         self.assertEqual(cf.sections(), sections)
01023         self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
01024         self.assertEqual(cf.getint("global", "max log size"), 50)
01025         self.assertEqual(cf.get("global", "hosts allow"), "127.")
01026         self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
01027 
01028 class ConfigParserTestCaseExtendedInterpolation(BasicTestCase):
01029     config_class = configparser.ConfigParser
01030     interpolation = configparser.ExtendedInterpolation()
01031     default_section = 'common'
01032     strict = True
01033 
01034     def fromstring(self, string, defaults=None, optionxform=None):
01035         cf = self.newconfig(defaults)
01036         if optionxform:
01037             cf.optionxform = optionxform
01038         cf.read_string(string)
01039         return cf
01040 
01041     def test_extended_interpolation(self):
01042         cf = self.fromstring(textwrap.dedent("""
01043             [common]
01044             favourite Beatle = Paul
01045             favourite color = green
01046 
01047             [tom]
01048             favourite band = ${favourite color} day
01049             favourite pope = John ${favourite Beatle} II
01050             sequel = ${favourite pope}I
01051 
01052             [ambv]
01053             favourite Beatle = George
01054             son of Edward VII = ${favourite Beatle} V
01055             son of George V = ${son of Edward VII}I
01056 
01057             [stanley]
01058             favourite Beatle = ${ambv:favourite Beatle}
01059             favourite pope = ${tom:favourite pope}
01060             favourite color = black
01061             favourite state of mind = paranoid
01062             favourite movie = soylent ${common:favourite color}
01063             favourite song = ${favourite color} sabbath - ${favourite state of mind}
01064         """).strip())
01065 
01066         eq = self.assertEqual
01067         eq(cf['common']['favourite Beatle'], 'Paul')
01068         eq(cf['common']['favourite color'], 'green')
01069         eq(cf['tom']['favourite Beatle'], 'Paul')
01070         eq(cf['tom']['favourite color'], 'green')
01071         eq(cf['tom']['favourite band'], 'green day')
01072         eq(cf['tom']['favourite pope'], 'John Paul II')
01073         eq(cf['tom']['sequel'], 'John Paul III')
01074         eq(cf['ambv']['favourite Beatle'], 'George')
01075         eq(cf['ambv']['favourite color'], 'green')
01076         eq(cf['ambv']['son of Edward VII'], 'George V')
01077         eq(cf['ambv']['son of George V'], 'George VI')
01078         eq(cf['stanley']['favourite Beatle'], 'George')
01079         eq(cf['stanley']['favourite color'], 'black')
01080         eq(cf['stanley']['favourite state of mind'], 'paranoid')
01081         eq(cf['stanley']['favourite movie'], 'soylent green')
01082         eq(cf['stanley']['favourite pope'], 'John Paul II')
01083         eq(cf['stanley']['favourite song'],
01084            'black sabbath - paranoid')
01085 
01086     def test_endless_loop(self):
01087         cf = self.fromstring(textwrap.dedent("""
01088             [one for you]
01089             ping = ${one for me:pong}
01090 
01091             [one for me]
01092             pong = ${one for you:ping}
01093 
01094             [selfish]
01095             me = ${me}
01096         """).strip())
01097 
01098         with self.assertRaises(configparser.InterpolationDepthError):
01099             cf['one for you']['ping']
01100         with self.assertRaises(configparser.InterpolationDepthError):
01101             cf['selfish']['me']
01102 
01103     def test_strange_options(self):
01104         cf = self.fromstring("""
01105             [dollars]
01106             $var = $$value
01107             $var2 = ${$var}
01108             ${sick} = cannot interpolate me
01109 
01110             [interpolated]
01111             $other = ${dollars:$var}
01112             $trying = ${dollars:${sick}}
01113         """)
01114 
01115         self.assertEqual(cf['dollars']['$var'], '$value')
01116         self.assertEqual(cf['interpolated']['$other'], '$value')
01117         self.assertEqual(cf['dollars']['${sick}'], 'cannot interpolate me')
01118         exception_class = configparser.InterpolationMissingOptionError
01119         with self.assertRaises(exception_class) as cm:
01120             cf['interpolated']['$trying']
01121         self.assertEqual(cm.exception.reference, 'dollars:${sick')
01122         self.assertEqual(cm.exception.args[2], '}') #rawval
01123 
01124     def test_case_sensitivity_basic(self):
01125         ini = textwrap.dedent("""
01126             [common]
01127             optionlower = value
01128             OptionUpper = Value
01129 
01130             [Common]
01131             optionlower = a better ${common:optionlower}
01132             OptionUpper = A Better ${common:OptionUpper}
01133 
01134             [random]
01135             foolower = ${common:optionlower} redefined
01136             FooUpper = ${Common:OptionUpper} Redefined
01137         """).strip()
01138 
01139         cf = self.fromstring(ini)
01140         eq = self.assertEqual
01141         eq(cf['common']['optionlower'], 'value')
01142         eq(cf['common']['OptionUpper'], 'Value')
01143         eq(cf['Common']['optionlower'], 'a better value')
01144         eq(cf['Common']['OptionUpper'], 'A Better Value')
01145         eq(cf['random']['foolower'], 'value redefined')
01146         eq(cf['random']['FooUpper'], 'A Better Value Redefined')
01147 
01148     def test_case_sensitivity_conflicts(self):
01149         ini = textwrap.dedent("""
01150             [common]
01151             option = value
01152             Option = Value
01153 
01154             [Common]
01155             option = a better ${common:option}
01156             Option = A Better ${common:Option}
01157 
01158             [random]
01159             foo = ${common:option} redefined
01160             Foo = ${Common:Option} Redefined
01161         """).strip()
01162         with self.assertRaises(configparser.DuplicateOptionError):
01163             cf = self.fromstring(ini)
01164 
01165         # raw options
01166         cf = self.fromstring(ini, optionxform=lambda opt: opt)
01167         eq = self.assertEqual
01168         eq(cf['common']['option'], 'value')
01169         eq(cf['common']['Option'], 'Value')
01170         eq(cf['Common']['option'], 'a better value')
01171         eq(cf['Common']['Option'], 'A Better Value')
01172         eq(cf['random']['foo'], 'value redefined')
01173         eq(cf['random']['Foo'], 'A Better Value Redefined')
01174 
01175     def test_other_errors(self):
01176         cf = self.fromstring("""
01177             [interpolation fail]
01178             case1 = ${where's the brace
01179             case2 = ${does_not_exist}
01180             case3 = ${wrong_section:wrong_value}
01181             case4 = ${i:like:colon:characters}
01182             case5 = $100 for Fail No 5!
01183         """)
01184 
01185         with self.assertRaises(configparser.InterpolationSyntaxError):
01186             cf['interpolation fail']['case1']
01187         with self.assertRaises(configparser.InterpolationMissingOptionError):
01188             cf['interpolation fail']['case2']
01189         with self.assertRaises(configparser.InterpolationMissingOptionError):
01190             cf['interpolation fail']['case3']
01191         with self.assertRaises(configparser.InterpolationSyntaxError):
01192             cf['interpolation fail']['case4']
01193         with self.assertRaises(configparser.InterpolationSyntaxError):
01194             cf['interpolation fail']['case5']
01195         with self.assertRaises(ValueError):
01196             cf['interpolation fail']['case6'] = "BLACK $ABBATH"
01197 
01198 
01199 class ConfigParserTestCaseNoValue(ConfigParserTestCase):
01200     allow_no_value = True
01201 
01202 class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
01203     config_class = configparser.ConfigParser
01204     delimiters = {'='}
01205     comment_prefixes = {'#'}
01206     allow_no_value = True
01207 
01208     def test_cfgparser_dot_3(self):
01209         tricky = support.findfile("cfgparser.3")
01210         cf = self.newconfig()
01211         self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
01212         self.assertEqual(cf.sections(), ['strange',
01213                                          'corruption',
01214                                          'yeah, sections can be '
01215                                          'indented as well',
01216                                          'another one!',
01217                                          'no values here',
01218                                          'tricky interpolation',
01219                                          'more interpolation'])
01220         self.assertEqual(cf.getint(self.default_section, 'go',
01221                                    vars={'interpolate': '-1'}), -1)
01222         with self.assertRaises(ValueError):
01223             # no interpolation will happen
01224             cf.getint(self.default_section, 'go', raw=True,
01225                       vars={'interpolate': '-1'})
01226         self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
01227         self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
01228         longname = 'yeah, sections can be indented as well'
01229         self.assertFalse(cf.getboolean(longname, 'are they subsections'))
01230         self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
01231         self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
01232                                                            # `go` from DEFAULT
01233         with self.assertRaises(configparser.InterpolationMissingOptionError):
01234             cf.items('no values here')
01235         self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
01236         self.assertEqual(cf.get('tricky interpolation', 'lets'),
01237                          cf.get('tricky interpolation', 'go'))
01238         self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
01239 
01240     def test_unicode_failure(self):
01241         tricky = support.findfile("cfgparser.3")
01242         cf = self.newconfig()
01243         with self.assertRaises(UnicodeDecodeError):
01244             cf.read(tricky, encoding='ascii')
01245 
01246 
01247 class Issue7005TestCase(unittest.TestCase):
01248     """Test output when None is set() as a value and allow_no_value == False.
01249 
01250     http://bugs.python.org/issue7005
01251 
01252     """
01253 
01254     expected_output = "[section]\noption = None\n\n"
01255 
01256     def prepare(self, config_class):
01257         # This is the default, but that's the point.
01258         cp = config_class(allow_no_value=False)
01259         cp.add_section("section")
01260         cp.set("section", "option", None)
01261         sio = io.StringIO()
01262         cp.write(sio)
01263         return sio.getvalue()
01264 
01265     def test_none_as_value_stringified(self):
01266         cp = configparser.ConfigParser(allow_no_value=False)
01267         cp.add_section("section")
01268         with self.assertRaises(TypeError):
01269             cp.set("section", "option", None)
01270 
01271     def test_none_as_value_stringified_raw(self):
01272         output = self.prepare(configparser.RawConfigParser)
01273         self.assertEqual(output, self.expected_output)
01274 
01275 
01276 class SortedTestCase(RawConfigParserTestCase):
01277     dict_type = SortedDict
01278 
01279     def test_sorted(self):
01280         cf = self.fromstring("[b]\n"
01281                              "o4=1\n"
01282                              "o3=2\n"
01283                              "o2=3\n"
01284                              "o1=4\n"
01285                              "[a]\n"
01286                              "k=v\n")
01287         output = io.StringIO()
01288         cf.write(output)
01289         self.assertEqual(output.getvalue(),
01290                          "[a]\n"
01291                          "k = v\n\n"
01292                          "[b]\n"
01293                          "o1 = 4\n"
01294                          "o2 = 3\n"
01295                          "o3 = 2\n"
01296                          "o4 = 1\n\n")
01297 
01298 
01299 class CompatibleTestCase(CfgParserTestCaseClass):
01300     config_class = configparser.RawConfigParser
01301     comment_prefixes = '#;'
01302     inline_comment_prefixes = ';'
01303 
01304     def test_comment_handling(self):
01305         config_string = textwrap.dedent("""\
01306         [Commented Bar]
01307         baz=qwe ; a comment
01308         foo: bar # not a comment!
01309         # but this is a comment
01310         ; another comment
01311         quirk: this;is not a comment
01312         ; a space must precede an inline comment
01313         """)
01314         cf = self.fromstring(config_string)
01315         self.assertEqual(cf.get('Commented Bar', 'foo'),
01316                          'bar # not a comment!')
01317         self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
01318         self.assertEqual(cf.get('Commented Bar', 'quirk'),
01319                          'this;is not a comment')
01320 
01321 class CopyTestCase(BasicTestCase):
01322     config_class = configparser.ConfigParser
01323 
01324     def fromstring(self, string, defaults=None):
01325         cf = self.newconfig(defaults)
01326         cf.read_string(string)
01327         cf_copy = self.newconfig()
01328         cf_copy.read_dict(cf)
01329         # we have to clean up option duplicates that appeared because of
01330         # the magic DEFAULTSECT behaviour.
01331         for section in cf_copy.values():
01332             if section.name == self.default_section:
01333                 continue
01334             for default, value in cf[self.default_section].items():
01335                 if section[default] == value:
01336                     del section[default]
01337         return cf_copy
01338 
01339 
01340 class FakeFile:
01341     def __init__(self):
01342         file_path = support.findfile("cfgparser.1")
01343         with open(file_path) as f:
01344             self.lines = f.readlines()
01345             self.lines.reverse()
01346 
01347     def readline(self):
01348         if len(self.lines):
01349             return self.lines.pop()
01350         return ''
01351 
01352 
01353 def readline_generator(f):
01354     """As advised in Doc/library/configparser.rst."""
01355     line = f.readline()
01356     while line:
01357         yield line
01358         line = f.readline()
01359 
01360 
01361 class ReadFileTestCase(unittest.TestCase):
01362     def test_file(self):
01363         file_path = support.findfile("cfgparser.1")
01364         parser = configparser.ConfigParser()
01365         with open(file_path) as f:
01366             parser.read_file(f)
01367         self.assertIn("Foo Bar", parser)
01368         self.assertIn("foo", parser["Foo Bar"])
01369         self.assertEqual(parser["Foo Bar"]["foo"], "newbar")
01370 
01371     def test_iterable(self):
01372         lines = textwrap.dedent("""
01373         [Foo Bar]
01374         foo=newbar""").strip().split('\n')
01375         parser = configparser.ConfigParser()
01376         parser.read_file(lines)
01377         self.assertIn("Foo Bar", parser)
01378         self.assertIn("foo", parser["Foo Bar"])
01379         self.assertEqual(parser["Foo Bar"]["foo"], "newbar")
01380 
01381     def test_readline_generator(self):
01382         """Issue #11670."""
01383         parser = configparser.ConfigParser()
01384         with self.assertRaises(TypeError):
01385             parser.read_file(FakeFile())
01386         parser.read_file(readline_generator(FakeFile()))
01387         self.assertIn("Foo Bar", parser)
01388         self.assertIn("foo", parser["Foo Bar"])
01389         self.assertEqual(parser["Foo Bar"]["foo"], "newbar")
01390 
01391 
01392 class CoverageOneHundredTestCase(unittest.TestCase):
01393     """Covers edge cases in the codebase."""
01394 
01395     def test_duplicate_option_error(self):
01396         error = configparser.DuplicateOptionError('section', 'option')
01397         self.assertEqual(error.section, 'section')
01398         self.assertEqual(error.option, 'option')
01399         self.assertEqual(error.source, None)
01400         self.assertEqual(error.lineno, None)
01401         self.assertEqual(error.args, ('section', 'option', None, None))
01402         self.assertEqual(str(error), "Option 'option' in section 'section' "
01403                                      "already exists")
01404 
01405     def test_interpolation_depth_error(self):
01406         error = configparser.InterpolationDepthError('option', 'section',
01407                                                      'rawval')
01408         self.assertEqual(error.args, ('option', 'section', 'rawval'))
01409         self.assertEqual(error.option, 'option')
01410         self.assertEqual(error.section, 'section')
01411 
01412     def test_parsing_error(self):
01413         with self.assertRaises(ValueError) as cm:
01414             configparser.ParsingError()
01415         self.assertEqual(str(cm.exception), "Required argument `source' not "
01416                                             "given.")
01417         with self.assertRaises(ValueError) as cm:
01418             configparser.ParsingError(source='source', filename='filename')
01419         self.assertEqual(str(cm.exception), "Cannot specify both `filename' "
01420                                             "and `source'. Use `source'.")
01421         error = configparser.ParsingError(filename='source')
01422         self.assertEqual(error.source, 'source')
01423         with warnings.catch_warnings(record=True) as w:
01424             warnings.simplefilter("always", DeprecationWarning)
01425             self.assertEqual(error.filename, 'source')
01426             error.filename = 'filename'
01427             self.assertEqual(error.source, 'filename')
01428         for warning in w:
01429             self.assertTrue(warning.category is DeprecationWarning)
01430 
01431     def test_interpolation_validation(self):
01432         parser = configparser.ConfigParser()
01433         parser.read_string("""
01434             [section]
01435             invalid_percent = %
01436             invalid_reference = %(()
01437             invalid_variable = %(does_not_exist)s
01438         """)
01439         with self.assertRaises(configparser.InterpolationSyntaxError) as cm:
01440             parser['section']['invalid_percent']
01441         self.assertEqual(str(cm.exception), "'%' must be followed by '%' or "
01442                                             "'(', found: '%'")
01443         with self.assertRaises(configparser.InterpolationSyntaxError) as cm:
01444             parser['section']['invalid_reference']
01445         self.assertEqual(str(cm.exception), "bad interpolation variable "
01446                                             "reference '%(()'")
01447 
01448     def test_readfp_deprecation(self):
01449         sio = io.StringIO("""
01450         [section]
01451         option = value
01452         """)
01453         parser = configparser.ConfigParser()
01454         with warnings.catch_warnings(record=True) as w:
01455             warnings.simplefilter("always", DeprecationWarning)
01456             parser.readfp(sio, filename='StringIO')
01457         for warning in w:
01458             self.assertTrue(warning.category is DeprecationWarning)
01459         self.assertEqual(len(parser), 2)
01460         self.assertEqual(parser['section']['option'], 'value')
01461 
01462     def test_safeconfigparser_deprecation(self):
01463         with warnings.catch_warnings(record=True) as w:
01464             warnings.simplefilter("always", DeprecationWarning)
01465             parser = configparser.SafeConfigParser()
01466         for warning in w:
01467             self.assertTrue(warning.category is DeprecationWarning)
01468 
01469     def test_sectionproxy_repr(self):
01470         parser = configparser.ConfigParser()
01471         parser.read_string("""
01472             [section]
01473             key = value
01474         """)
01475         self.assertEqual(repr(parser['section']), '<Section: section>')
01476 
01477 def test_main():
01478     support.run_unittest(
01479         ConfigParserTestCase,
01480         ConfigParserTestCaseNonStandardDelimiters,
01481         ConfigParserTestCaseNoValue,
01482         ConfigParserTestCaseExtendedInterpolation,
01483         ConfigParserTestCaseLegacyInterpolation,
01484         ConfigParserTestCaseNoInterpolation,
01485         ConfigParserTestCaseTrickyFile,
01486         MultilineValuesTestCase,
01487         RawConfigParserTestCase,
01488         RawConfigParserTestCaseNonStandardDelimiters,
01489         RawConfigParserTestSambaConf,
01490         SortedTestCase,
01491         Issue7005TestCase,
01492         StrictTestCase,
01493         CompatibleTestCase,
01494         CopyTestCase,
01495         ConfigParserTestCaseNonStandardDefaultSection,
01496         ReadFileTestCase,
01497         CoverageOneHundredTestCase,
01498         )