diff options
Diffstat (limited to 'Lib/test/test_cfgparser.py')
-rw-r--r-- | Lib/test/test_cfgparser.py | 280 |
1 files changed, 185 insertions, 95 deletions
diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py index c5a2595..e00a51a 100644 --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -3,6 +3,7 @@ import configparser import io import os import unittest +import textwrap from test import support @@ -23,15 +24,26 @@ class SortedDict(collections.UserDict): def itervalues(self): return iter(self.values()) -class TestCaseBase(unittest.TestCase): +class CfgParserTestCaseClass(unittest.TestCase): allow_no_value = False + delimiters = ('=', ':') + comment_prefixes = (';', '#') + empty_lines_in_values = True + dict_type = configparser._default_dict def newconfig(self, defaults=None): + arguments = dict( + allow_no_value=self.allow_no_value, + delimiters=self.delimiters, + comment_prefixes=self.comment_prefixes, + empty_lines_in_values=self.empty_lines_in_values, + dict_type=self.dict_type, + ) if defaults is None: - self.cf = self.config_class(allow_no_value=self.allow_no_value) + self.cf = self.config_class(**arguments) else: self.cf = self.config_class(defaults, - allow_no_value=self.allow_no_value) + **arguments) return self.cf def fromstring(self, string, defaults=None): @@ -40,27 +52,33 @@ class TestCaseBase(unittest.TestCase): cf.readfp(sio) return cf +class BasicTestCase(CfgParserTestCaseClass): + def test_basic(self): - config_string = ( - "[Foo Bar]\n" - "foo=bar\n" - "[Spacey Bar]\n" - "foo = bar\n" - "[Commented Bar]\n" - "foo: bar ; comment\n" - "[Long Line]\n" - "foo: this line is much, much longer than my editor\n" - " likes it.\n" - "[Section\\with$weird%characters[\t]\n" - "[Internationalized Stuff]\n" - "foo[bg]: Bulgarian\n" - "foo=Default\n" - "foo[en]=English\n" - "foo[de]=Deutsch\n" - "[Spaces]\n" - "key with spaces : value\n" - "another with spaces = splat!\n" - ) + config_string = """\ +[Foo Bar] +foo{0[0]}bar +[Spacey Bar] +foo {0[0]} bar +[Spacey Bar From The Beginning] + foo {0[0]} bar + baz {0[0]} qwe +[Commented Bar] +foo{0[1]} bar {1[1]} comment +baz{0[0]}qwe {1[0]}another one +[Long Line] +foo{0[1]} this line is much, much longer than my editor + likes it. +[Section\\with$weird%characters[\t] +[Internationalized Stuff] +foo[bg]{0[1]} Bulgarian +foo{0[0]}Default +foo[en]{0[0]}English +foo[de]{0[0]}Deutsch +[Spaces] +key with spaces {0[1]} value +another with spaces {0[0]} splat! +""".format(self.delimiters, self.comment_prefixes) if self.allow_no_value: config_string += ( "[NoValue]\n" @@ -70,13 +88,14 @@ class TestCaseBase(unittest.TestCase): cf = self.fromstring(config_string) L = cf.sections() L.sort() - E = [r'Commented Bar', - r'Foo Bar', - r'Internationalized Stuff', - r'Long Line', - r'Section\with$weird%characters[' '\t', - r'Spaces', - r'Spacey Bar', + E = ['Commented Bar', + 'Foo Bar', + 'Internationalized Stuff', + 'Long Line', + 'Section\\with$weird%characters[\t', + 'Spaces', + 'Spacey Bar', + 'Spacey Bar From The Beginning', ] if self.allow_no_value: E.append(r'NoValue') @@ -89,7 +108,10 @@ class TestCaseBase(unittest.TestCase): # http://www.python.org/sf/583248 eq(cf.get('Foo Bar', 'foo'), 'bar') eq(cf.get('Spacey Bar', 'foo'), 'bar') + eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar') + eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe') eq(cf.get('Commented Bar', 'foo'), 'bar') + eq(cf.get('Commented Bar', 'baz'), 'qwe') eq(cf.get('Spaces', 'key with spaces'), 'value') eq(cf.get('Spaces', 'another with spaces'), 'splat!') if self.allow_no_value: @@ -140,12 +162,14 @@ class TestCaseBase(unittest.TestCase): # SF bug #432369: cf = self.fromstring( - "[MySection]\nOption: first line\n\tsecond line\n") + "[MySection]\nOption{} first line\n\tsecond line\n".format( + self.delimiters[0])) eq(cf.options("MySection"), ["option"]) eq(cf.get("MySection", "Option"), "first line\nsecond line") # SF bug #561822: - cf = self.fromstring("[section]\nnekey=nevalue\n", + cf = self.fromstring("[section]\n" + "nekey{}nevalue\n".format(self.delimiters[0]), defaults={"key":"value"}) self.assertTrue(cf.has_option("section", "Key")) @@ -162,18 +186,19 @@ class TestCaseBase(unittest.TestCase): def test_parse_errors(self): self.newconfig() - e = self.parse_error(configparser.ParsingError, - "[Foo]\n extra-spaces: splat\n") - self.assertEqual(e.args, ('<???>',)) - self.parse_error(configparser.ParsingError, - "[Foo]\n extra-spaces= splat\n") self.parse_error(configparser.ParsingError, - "[Foo]\n:value-without-option-name\n") + "[Foo]\n" + "{}val-without-opt-name\n".format(self.delimiters[0])) self.parse_error(configparser.ParsingError, - "[Foo]\n=value-without-option-name\n") + "[Foo]\n" + "{}val-without-opt-name\n".format(self.delimiters[1])) e = self.parse_error(configparser.MissingSectionHeaderError, "No Section!\n") self.assertEqual(e.args, ('<???>', 1, "No Section!\n")) + if not self.allow_no_value: + e = self.parse_error(configparser.ParsingError, + "[Foo]\n wrong-indent\n") + self.assertEqual(e.args, ('<???>',)) def parse_error(self, exc, src): sio = io.StringIO(src) @@ -188,9 +213,9 @@ class TestCaseBase(unittest.TestCase): self.assertFalse(cf.has_section("Foo"), "new ConfigParser should have no acknowledged " "sections") - with self.assertRaises(configparser.NoSectionError) as cm: + with self.assertRaises(configparser.NoSectionError): cf.options("Foo") - with self.assertRaises(configparser.NoSectionError) as cm: + with self.assertRaises(configparser.NoSectionError): cf.set("foo", "bar", "value") e = self.get_error(configparser.NoSectionError, "foo", "bar") self.assertEqual(e.args, ("foo",)) @@ -210,21 +235,21 @@ class TestCaseBase(unittest.TestCase): def test_boolean(self): cf = self.fromstring( "[BOOLTEST]\n" - "T1=1\n" - "T2=TRUE\n" - "T3=True\n" - "T4=oN\n" - "T5=yes\n" - "F1=0\n" - "F2=FALSE\n" - "F3=False\n" - "F4=oFF\n" - "F5=nO\n" - "E1=2\n" - "E2=foo\n" - "E3=-1\n" - "E4=0.1\n" - "E5=FALSE AND MORE" + "T1{equals}1\n" + "T2{equals}TRUE\n" + "T3{equals}True\n" + "T4{equals}oN\n" + "T5{equals}yes\n" + "F1{equals}0\n" + "F2{equals}FALSE\n" + "F3{equals}False\n" + "F4{equals}oFF\n" + "F5{equals}nO\n" + "E1{equals}2\n" + "E2{equals}foo\n" + "E3{equals}-1\n" + "E4{equals}0.1\n" + "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0]) ) for x in range(1, 5): self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x)) @@ -242,11 +267,17 @@ class TestCaseBase(unittest.TestCase): def test_write(self): config_string = ( "[Long Line]\n" - "foo: this line is much, much longer than my editor\n" + "foo{0[0]} this line is much, much longer than my editor\n" " likes it.\n" "[DEFAULT]\n" - "foo: another very\n" + "foo{0[1]} another very\n" " long line\n" + "[Long Line - With Comments!]\n" + "test {0[1]} we {comment} can\n" + " also {comment} place\n" + " comments {comment} in\n" + " multiline {comment} values" + "\n".format(self.delimiters, comment=self.comment_prefixes[0]) ) if self.allow_no_value: config_string += ( @@ -259,13 +290,19 @@ class TestCaseBase(unittest.TestCase): cf.write(output) expect_string = ( "[DEFAULT]\n" - "foo = another very\n" + "foo {equals} another very\n" "\tlong line\n" "\n" "[Long Line]\n" - "foo = this line is much, much longer than my editor\n" + "foo {equals} this line is much, much longer than my editor\n" "\tlikes it.\n" "\n" + "[Long Line - With Comments!]\n" + "test {equals} we\n" + "\talso\n" + "\tcomments\n" + "\tmultiline\n" + "\n".format(equals=self.delimiters[0]) ) if self.allow_no_value: expect_string += ( @@ -277,7 +314,7 @@ class TestCaseBase(unittest.TestCase): def test_set_string_types(self): cf = self.fromstring("[sect]\n" - "option1=foo\n") + "option1{eq}foo\n".format(eq=self.delimiters[0])) # Check that we don't get an exception when setting values in # an existing section using strings: class mystr(str): @@ -290,6 +327,9 @@ class TestCaseBase(unittest.TestCase): cf.set("sect", "option2", "splat") def test_read_returns_file_list(self): + if self.delimiters[0] != '=': + # skip reading the file if we're using an incompatible format + return file1 = support.findfile("cfgparser.1") # check when we pass a mix of readable and non-readable files: cf = self.newconfig() @@ -314,45 +354,45 @@ class TestCaseBase(unittest.TestCase): def get_interpolation_config(self): return self.fromstring( "[Foo]\n" - "bar=something %(with1)s interpolation (1 step)\n" - "bar9=something %(with9)s lots of interpolation (9 steps)\n" - "bar10=something %(with10)s lots of interpolation (10 steps)\n" - "bar11=something %(with11)s lots of interpolation (11 steps)\n" - "with11=%(with10)s\n" - "with10=%(with9)s\n" - "with9=%(with8)s\n" - "with8=%(With7)s\n" - "with7=%(WITH6)s\n" - "with6=%(with5)s\n" - "With5=%(with4)s\n" - "WITH4=%(with3)s\n" - "with3=%(with2)s\n" - "with2=%(with1)s\n" - "with1=with\n" + "bar{equals}something %(with1)s interpolation (1 step)\n" + "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n" + "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n" + "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n" + "with11{equals}%(with10)s\n" + "with10{equals}%(with9)s\n" + "with9{equals}%(with8)s\n" + "with8{equals}%(With7)s\n" + "with7{equals}%(WITH6)s\n" + "with6{equals}%(with5)s\n" + "With5{equals}%(with4)s\n" + "WITH4{equals}%(with3)s\n" + "with3{equals}%(with2)s\n" + "with2{equals}%(with1)s\n" + "with1{equals}with\n" "\n" "[Mutual Recursion]\n" - "foo=%(bar)s\n" - "bar=%(foo)s\n" + "foo{equals}%(bar)s\n" + "bar{equals}%(foo)s\n" "\n" "[Interpolation Error]\n" - "name=%(reference)s\n", + "name{equals}%(reference)s\n".format(equals=self.delimiters[0]), # no definition for 'reference' defaults={"getname": "%(__name__)s"}) def check_items_config(self, expected): cf = self.fromstring( "[section]\n" - "name = value\n" - "key: |%(name)s| \n" - "getdefault: |%(default)s|\n" - "getname: |%(__name__)s|", + "name {0[0]} value\n" + "key{0[1]} |%(name)s| \n" + "getdefault{0[1]} |%(default)s|\n" + "getname{0[1]} |%(__name__)s|".format(self.delimiters), defaults={"default": "<default>"}) L = list(cf.items("section")) L.sort() self.assertEqual(L, expected) -class ConfigParserTestCase(TestCaseBase): +class ConfigParserTestCase(BasicTestCase): config_class = configparser.ConfigParser def test_interpolation(self): @@ -414,7 +454,11 @@ class ConfigParserTestCase(TestCaseBase): self.assertRaises(ValueError, cf.get, 'non-string', 'string_with_interpolation', raw=False) -class MultilineValuesTestCase(TestCaseBase): +class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase): + delimiters = (':=', '$') + comment_prefixes = ('//', '"') + +class MultilineValuesTestCase(BasicTestCase): config_class = configparser.ConfigParser wonderful_spam = ("I'm having spam spam spam spam " "spam spam spam beaked beans spam " @@ -442,7 +486,7 @@ class MultilineValuesTestCase(TestCaseBase): self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'), self.wonderful_spam.replace('\t\n', '\n')) -class RawConfigParserTestCase(TestCaseBase): +class RawConfigParserTestCase(BasicTestCase): config_class = configparser.RawConfigParser def test_interpolation(self): @@ -476,6 +520,28 @@ class RawConfigParserTestCase(TestCaseBase): [0, 1, 1, 2, 3, 5, 8, 13]) self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159}) +class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase): + delimiters = (':=', '$') + comment_prefixes = ('//', '"') + +class RawConfigParserTestSambaConf(BasicTestCase): + config_class = configparser.RawConfigParser + comment_prefixes = ('#', ';', '//', '----') + empty_lines_in_values = False + + def test_reading(self): + smbconf = support.findfile("cfgparser.2") + # check when we pass a mix of readable and non-readable files: + cf = self.newconfig() + parsed_files = cf.read([smbconf, "nonexistent-file"]) + self.assertEqual(parsed_files, [smbconf]) + sections = ['global', 'homes', 'printers', + 'print$', 'pdf-generator', 'tmp', 'Agustin'] + self.assertEqual(cf.sections(), sections) + self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP") + self.assertEqual(cf.getint("global", "max log size"), 50) + self.assertEqual(cf.get("global", "hosts allow"), "127.") + self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s") class SafeConfigParserTestCase(ConfigParserTestCase): config_class = configparser.SafeConfigParser @@ -483,16 +549,17 @@ class SafeConfigParserTestCase(ConfigParserTestCase): def test_safe_interpolation(self): # See http://www.python.org/sf/511737 cf = self.fromstring("[section]\n" - "option1=xxx\n" - "option2=%(option1)s/xxx\n" - "ok=%(option1)s/%%s\n" - "not_ok=%(option2)s/%%s") + "option1{eq}xxx\n" + "option2{eq}%(option1)s/xxx\n" + "ok{eq}%(option1)s/%%s\n" + "not_ok{eq}%(option2)s/%%s".format( + eq=self.delimiters[0])) self.assertEqual(cf.get("section", "ok"), "xxx/%s") self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") def test_set_malformatted_interpolation(self): cf = self.fromstring("[sect]\n" - "option1=foo\n") + "option1{eq}foo\n".format(eq=self.delimiters[0])) self.assertEqual(cf.get('sect', "option1"), "foo") @@ -508,7 +575,7 @@ class SafeConfigParserTestCase(ConfigParserTestCase): def test_set_nonstring_types(self): cf = self.fromstring("[sect]\n" - "option1=foo\n") + "option1{eq}foo\n".format(eq=self.delimiters[0])) # Check that we get a TypeError when setting non-string values # in an existing section: self.assertRaises(TypeError, cf.set, "sect", "option1", 1) @@ -526,15 +593,16 @@ class SafeConfigParserTestCase(ConfigParserTestCase): cf = self.newconfig() self.assertRaises(ValueError, cf.add_section, "DEFAULT") +class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase): + delimiters = (':=', '$') + comment_prefixes = ('//', '"') class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase): allow_no_value = True class SortedTestCase(RawConfigParserTestCase): - def newconfig(self, defaults=None): - self.cf = self.config_class(defaults=defaults, dict_type=SortedDict) - return self.cf + dict_type = SortedDict def test_sorted(self): self.fromstring("[b]\n" @@ -556,14 +624,36 @@ class SortedTestCase(RawConfigParserTestCase): "o4 = 1\n\n") +class CompatibleTestCase(CfgParserTestCaseClass): + config_class = configparser.RawConfigParser + comment_prefixes = configparser.RawConfigParser._COMPATIBLE + + def test_comment_handling(self): + config_string = textwrap.dedent("""\ + [Commented Bar] + baz=qwe ; a comment + foo: bar # not a comment! + # but this is a comment + ; another comment + """) + cf = self.fromstring(config_string) + self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!') + self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe') + + def test_main(): support.run_unittest( ConfigParserTestCase, + ConfigParserTestCaseNonStandardDelimiters, MultilineValuesTestCase, RawConfigParserTestCase, + RawConfigParserTestCaseNonStandardDelimiters, + RawConfigParserTestSambaConf, SafeConfigParserTestCase, + SafeConfigParserTestCaseNonStandardDelimiters, SafeConfigParserTestCaseNoValue, SortedTestCase, + CompatibleTestCase, ) |