← Back to team overview

configglue team mailing list archive

[Merge] lp:~ricardokirkner/configglue/bag-of-improvements into lp:configglue

 

Ricardo Kirkner has proposed merging lp:~ricardokirkner/configglue/bag-of-improvements into lp:configglue.

Requested reviews:
  Configglue developers (configglue)

For more details, see:
https://code.launchpad.net/~ricardokirkner/configglue/bag-of-improvements/+merge/69795

several small improvements
-- 
https://code.launchpad.net/~ricardokirkner/configglue/bag-of-improvements/+merge/69795
Your team Configglue developers is requested to review the proposed merge of lp:~ricardokirkner/configglue/bag-of-improvements into lp:configglue.
=== modified file 'configglue/parser.py'
--- configglue/parser.py	2011-07-28 23:10:26 +0000
+++ configglue/parser.py	2011-07-29 13:56:41 +0000
@@ -166,6 +166,10 @@
         else:
             return valid
 
+    def optionxform(self, optionstr):
+        # allow case-sensitive options
+        return optionstr
+
     def items(self, section, raw=False, vars=None):
         """Return the list of all options in a section.
 
@@ -261,6 +265,7 @@
             self._read(fp, path, already_read=already_read)
             fp.close()
             read_ok.append(path)
+            self._last_location = filename
         return read_ok
 
     def readfp(self, fp, filename=None):
@@ -278,11 +283,11 @@
         already_read.add(fpname)
 
         if self.has_option('__main__', 'includes'):
-            old_basedir, self._basedir = self._basedir, os.path.dirname(fpname)
+            old_basedir, self._basedir = self._basedir, os.path.dirname(
+                fpname)
             includes = self.get('__main__', 'includes')
             filenames = map(string.strip, includes)
-            for filename in filenames:
-                self.read(filename, already_read=already_read)
+            self.read(filenames, already_read=already_read)
             self._basedir = old_basedir
 
             if filenames:
@@ -552,6 +557,9 @@
 
     def write(self, fp):
         """Write an .ini-format representation of the configuration state."""
+        # make sure the parser is populated
+        self._fill_parser()
+
         if self._defaults:
             fp.write("[%s]\n" % DEFAULTSECT)
             for (key, value) in self._defaults.items():
@@ -583,6 +591,18 @@
             # write to the original files
             for filename, sections in self._dirty.items():
 
+                if filename is None:
+                    # default option was overridden. figure out where to
+                    # save it
+                    if not getattr(self, '_last_location', None):
+                        # no files where read, there is no possible
+                        # location for the customized setting.
+                        raise ValueError("No config files where read and no "
+                            "location was specified for writing the "
+                            "configuration.")
+                    else:
+                        filename = self._last_location
+
                 parser = BaseConfigParser()
                 parser.read(filename)
 
@@ -597,3 +617,12 @@
                     os.rename(filename, "%s.old" % filename)
                 # rename new file
                 os.rename("%s.new" % filename, filename)
+
+    def _fill_parser(self):
+        """Populate parser with current values for each option."""
+        values = self.values()
+        for section, options in values.items():
+            for option, value in options.items():
+                self.set(section, option, value)
+        # make sure having set the options didn't change anything
+        assert values == self.values()

=== modified file 'configglue/tests/test_parser.py'
--- configglue/tests/test_parser.py	2011-07-28 23:10:26 +0000
+++ configglue/tests/test_parser.py	2011-07-29 13:56:41 +0000
@@ -572,6 +572,30 @@
         values = self.parser.values(section='__main__')
         self.assertEqual(expected_values['__main__'], values)
 
+    def test_values_case_sensitive_options(self):
+        class MySchema(Schema):
+            foo = DictOption()
+        parser = SchemaConfigParser(MySchema())
+        config = StringIO(textwrap.dedent("""
+            [__main__]
+            foo = mydict
+            [mydict]
+            lowercase = lowercase
+            UPPERCASE = UPPERCASE
+            MixedCase = MixedCase
+            """))
+        parser.readfp(config)
+
+        self.assertEqual(parser.values(), {
+            '__main__': {
+                'foo': {
+                    'lowercase': 'lowercase',
+                    'UPPERCASE': 'UPPERCASE',
+                    'MixedCase': 'MixedCase',
+                },
+            },
+        })
+
     def test_values_many_sections_same_option(self):
         """Test parser.values for many section with the same option."""
         class MySchema(Schema):
@@ -759,6 +783,11 @@
         self.assertRaises(NoSectionError, self.parser._get_default,
             'foo', 'bar')
 
+    def test_optionxform(self):
+        self.assertEqual(self.parser.optionxform('lowercase'), 'lowercase')
+        self.assertEqual(self.parser.optionxform('UPPERCASE'), 'UPPERCASE')
+        self.assertEqual(self.parser.optionxform('MixedCase'), 'MixedCase')
+
     def test_multi_file_dict_config(self):
         """Test parsing a dict option spanning multiple files."""
         class MySchema(Schema):
@@ -912,6 +941,24 @@
             # remove the file
             os.unlink(filename)
 
+    def test_write_prefill_parser(self):
+        """Test parser write config to a file."""
+        class MySchema(Schema):
+            foo = IntOption()
+
+        parser = SchemaConfigParser(MySchema())
+        expected = u"[__main__]\nfoo = 0"
+
+        # create config file
+        fp, filename = tempfile.mkstemp()
+        try:
+            parser.write(open(filename, 'w'))
+            result = open(filename, 'r').read().strip()
+            self.assertEqual(result, expected)
+        finally:
+            # remove the file
+            os.unlink(filename)
+
     def test_save_config(self):
         expected = u'[__main__]\nfoo = 42'
         self._check_save_file(expected)
@@ -920,9 +967,10 @@
         expected = u'[__main__]\nfoo = fóobâr'
         self._check_save_file(expected)
 
-    def _check_save_file(self, expected):
+    def _check_save_file(self, expected, read_config=True):
         config = StringIO(expected.encode(CONFIG_FILE_ENCODING))
-        self.parser.readfp(config)
+        if read_config:
+            self.parser.readfp(config)
 
         # create config file
         fp, filename = tempfile.mkstemp()
@@ -938,6 +986,19 @@
             # remove the file
             os.unlink(filename)
 
+    def test_save_config_prefill_parser(self):
+        """Test parser save config when no config files read."""
+        expected = u'[__main__]\nfoo ='
+        self._check_save_file(expected, read_config=False)
+
+    def test_save_no_config_same_files(self):
+        class MySchema(Schema):
+            foo = IntOption()
+
+        parser = SchemaConfigParser(MySchema())
+        parser.set('__main__', 'foo', 2)
+        self.assertRaises(ValueError, parser.save)
+
     def test_save_config_same_files(self):
         """Test parser save config values to original files."""
         def setup_config():
@@ -957,6 +1018,7 @@
         class MySchema(Schema):
             foo = StringOption()
             bar = StringOption()
+            baz = IntOption()
 
         self.parser = SchemaConfigParser(MySchema())
 
@@ -964,15 +1026,70 @@
         self.parser.read(files)
         self.parser.set('__main__', 'foo', '42')
         self.parser.set('__main__', 'bar', '42')
+        self.parser.set('__main__', 'baz', 42)
         self.parser.save()
 
         # test the changes were correctly saved
         data = open("%s/first.cfg" % folder).read()
         self.assertTrue('foo = 42' in data)
         self.assertFalse('bar = 42' in data)
+        # new value goes into last read config file
+        self.assertFalse('baz = 42' in data)
         data = open("%s/second.cfg" % folder).read()
         self.assertFalse('foo = 42' in data)
         self.assertTrue('bar = 42' in data)
+        # new value goes into last read config file
+        self.assertTrue('baz = 42' in data)
+
+        # silently remove any created files
+        try:
+            shutil.rmtree(folder)
+        except:
+            pass
+
+    def test_save_config_last_location_nested_includes(self):
+        def setup_config():
+            folder = tempfile.mkdtemp()
+
+            f = open("%s/first.cfg" % folder, 'w')
+            f.write("[__main__]\nfoo=1")
+            f.close()
+
+            f = open("%s/second.cfg" % folder, 'w')
+            f.write("[__main__]\nbar=2\nincludes = third.cfg")
+            f.close()
+
+            f = open("%s/third.cfg" % folder, 'w')
+            f.write("[__main__]\nfoo=3")
+            f.close()
+
+            files = ["%s/first.cfg" % folder, "%s/second.cfg" % folder]
+            return files, folder
+
+        class MySchema(Schema):
+            foo = StringOption()
+            bar = StringOption()
+            baz = IntOption()
+
+        self.parser = SchemaConfigParser(MySchema())
+
+        files, folder = setup_config()
+        self.parser.read(files)
+        self.parser.set('__main__', 'foo', '42')
+        self.parser.set('__main__', 'bar', '42')
+        self.parser.set('__main__', 'baz', 42)
+        self.parser.save()
+
+        # test the changes were correctly saved
+        data = open("%s/first.cfg" % folder).read()
+        self.assertEqual(data.strip(), '[__main__]\nfoo=1')
+        data = open("%s/third.cfg" % folder).read()
+        self.assertEqual(data.strip(), '[__main__]\nfoo = 42')
+        data = open("%s/second.cfg" % folder).read()
+        self.assertTrue('bar = 42' in data)
+        # new value goes into last read config file
+        # not in the last included config file
+        self.assertTrue('baz = 42' in data)
 
         # silently remove any created files
         try:


Follow ups