[Python-checkins] r83154 - in python/branches/py3k/Lib: configparser.py test/test_cfgparser.py

brian.curtin python-checkins at python.org
Mon Jul 26 02:27:10 CEST 2010


Author: brian.curtin
Date: Mon Jul 26 02:27:10 2010
New Revision: 83154

Log:
Fix #7113. Patch by Łukasz Langa.

Changes include using a list of lines instead of patching together using
string interpolation, and a multi-line value test cases.


Modified:
   python/branches/py3k/Lib/configparser.py
   python/branches/py3k/Lib/test/test_cfgparser.py

Modified: python/branches/py3k/Lib/configparser.py
==============================================================================
--- python/branches/py3k/Lib/configparser.py	(original)
+++ python/branches/py3k/Lib/configparser.py	Mon Jul 26 02:27:10 2010
@@ -405,12 +405,11 @@
         for section in self._sections:
             fp.write("[%s]\n" % section)
             for (key, value) in self._sections[section].items():
-                if key != "__name__":
-                    if value is None:
-                        fp.write("%s\n" % (key))
-                    else:
-                        fp.write("%s = %s\n" %
-                                 (key, str(value).replace('\n', '\n\t')))
+                if key == "__name__":
+                    continue
+                if value is not None:
+                    key = " = ".join((key, str(value).replace('\n', '\n\t')))
+                fp.write("%s\n" % (key))
             fp.write("\n")
 
     def remove_option(self, section, option):
@@ -471,10 +470,10 @@
         leading whitespace.  Blank lines, lines beginning with a '#',
         and just about everything else are ignored.
         """
-        cursect = None                            # None, or a dictionary
+        cursect = None                        # None, or a dictionary
         optname = None
         lineno = 0
-        e = None                                  # None, or an exception
+        e = None                              # None, or an exception
         while True:
             line = fp.readline()
             if not line:
@@ -490,7 +489,7 @@
             if line[0].isspace() and cursect is not None and optname:
                 value = line.strip()
                 if value:
-                    cursect[optname] = "%s\n%s" % (cursect[optname], value)
+                    cursect[optname].append(value)
             # a section header or option header?
             else:
                 # is it a section header?
@@ -515,6 +514,7 @@
                     mo = self._optcre.match(line)
                     if mo:
                         optname, vi, optval = mo.group('option', 'vi', 'value')
+                        optname = self.optionxform(optname.rstrip())
                         # This check is fine because the OPTCRE cannot
                         # match if it would set optval to None
                         if optval is not None:
@@ -525,11 +525,13 @@
                                 if pos != -1 and optval[pos-1].isspace():
                                     optval = optval[:pos]
                             optval = optval.strip()
-                        # allow empty values
-                        if optval == '""':
-                            optval = ''
-                        optname = self.optionxform(optname.rstrip())
-                        cursect[optname] = optval
+                            # allow empty values
+                            if optval == '""':
+                                optval = ''
+                            cursect[optname] = [optval]
+                        else:
+                            # valueless option handling
+                            cursect[optname] = optval
                     else:
                         # a non-fatal parsing error occurred.  set up the
                         # exception but keep going. the exception will be
@@ -542,6 +544,13 @@
         if e:
             raise e
 
+        # join the multi-line values collected while reading
+        all_sections = [self._defaults]
+        all_sections.extend(self._sections.values())
+        for options in all_sections:
+            for name, val in options.items():
+                if isinstance(val, list):
+                    options[name] = '\n'.join(val)
 
 class ConfigParser(RawConfigParser):
 

Modified: python/branches/py3k/Lib/test/test_cfgparser.py
==============================================================================
--- python/branches/py3k/Lib/test/test_cfgparser.py	(original)
+++ python/branches/py3k/Lib/test/test_cfgparser.py	Mon Jul 26 02:27:10 2010
@@ -1,7 +1,8 @@
+import collections
 import configparser
 import io
+import os
 import unittest
-import collections
 
 from test import support
 
@@ -162,7 +163,7 @@
     def test_parse_errors(self):
         self.newconfig()
         e = self.parse_error(configparser.ParsingError,
-                         "[Foo]\n  extra-spaces: splat\n")
+                             "[Foo]\n  extra-spaces: splat\n")
         self.assertEqual(e.args, ('<???>',))
         self.parse_error(configparser.ParsingError,
                          "[Foo]\n  extra-spaces= splat\n")
@@ -171,7 +172,7 @@
         self.parse_error(configparser.ParsingError,
                          "[Foo]\n=value-without-option-name\n")
         e = self.parse_error(configparser.MissingSectionHeaderError,
-                         "No Section!\n")
+                             "No Section!\n")
         self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
 
     def parse_error(self, exc, src):
@@ -185,7 +186,8 @@
         self.assertEqual(cf.sections(), [],
                          "new ConfigParser should have no defined sections")
         self.assertFalse(cf.has_section("Foo"),
-                    "new ConfigParser should have no acknowledged sections")
+                         "new ConfigParser should have no acknowledged "
+                         "sections")
         with self.assertRaises(configparser.NoSectionError) as cm:
             cf.options("Foo")
         with self.assertRaises(configparser.NoSectionError) as cm:
@@ -355,8 +357,8 @@
 
     def test_interpolation(self):
         rawval = {
-            configparser.ConfigParser: "something %(with11)s "\
-                                           "lots of interpolation (11 steps)",
+            configparser.ConfigParser: ("something %(with11)s "
+                                        "lots of interpolation (11 steps)"),
             configparser.SafeConfigParser: "%(with1)s",
         }
         cf = self.get_interpolation_config()
@@ -412,6 +414,33 @@
         self.assertRaises(ValueError, cf.get, 'non-string',
                           'string_with_interpolation', raw=False)
 
+class MultilineValuesTestCase(TestCaseBase):
+    config_class = configparser.ConfigParser
+    wonderful_spam = ("I'm having spam spam spam spam "
+                      "spam spam spam beaked beans spam "
+                      "spam spam and spam!").replace(' ', '\t\n')
+
+    def setUp(self):
+        cf = self.newconfig()
+        for i in range(100):
+            s = 'section{}'.format(i)
+            cf.add_section(s)
+            for j in range(10):
+                cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
+        with open(support.TESTFN, 'w') as f:
+            cf.write(f)
+
+    def tearDown(self):
+        os.unlink(support.TESTFN)
+
+    def test_dominating_multiline_values(self):
+        # We're reading from file because this is where the code changed
+        # during performance updates in Python 3.2
+        cf_from_file = self.newconfig()
+        with open(support.TESTFN) as f:
+            cf_from_file.readfp(f)
+        self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
+                         self.wonderful_spam.replace('\t\n', '\n'))
 
 class RawConfigParserTestCase(TestCaseBase):
     config_class = configparser.RawConfigParser
@@ -530,10 +559,11 @@
 def test_main():
     support.run_unittest(
         ConfigParserTestCase,
+        MultilineValuesTestCase,
         RawConfigParserTestCase,
         SafeConfigParserTestCase,
-        SortedTestCase,
         SafeConfigParserTestCaseNoValue,
+        SortedTestCase,
         )
 
 


More information about the Python-checkins mailing list