configglue team mailing list archive
-
configglue team
-
Mailing list archive
-
Message #00327
[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