configglue team mailing list archive
-
configglue team
-
Mailing list archive
-
Message #00330
[Merge] lp:~ricardokirkner/configglue/json-dicts into lp:configglue
Ricardo Kirkner has proposed merging lp:~ricardokirkner/configglue/json-dicts into lp:configglue.
Requested reviews:
Configglue developers (configglue)
For more details, see:
https://code.launchpad.net/~ricardokirkner/configglue/json-dicts/+merge/69863
allow DictOptions to be specified in the config using json
--
https://code.launchpad.net/~ricardokirkner/configglue/json-dicts/+merge/69863
Your team Configglue developers is requested to review the proposed merge of lp:~ricardokirkner/configglue/json-dicts into lp:configglue.
=== modified file 'configglue/parser.py'
--- configglue/parser.py 2011-07-28 23:10:26 +0000
+++ configglue/parser.py 2011-07-29 21:33:28 +0000
@@ -347,25 +347,6 @@
if option_obj.require_parser:
kwargs = {'parser': self}
- # hook to save extra sections
- is_dict_option = isinstance(option_obj, DictOption)
- is_dict_lines_option = (hasattr(option_obj, 'item') and
- isinstance(option_obj.item, DictOption))
-
- # avoid adding implicit sections for dict default value
- if (is_dict_option or is_dict_lines_option):
- sections = value.split()
- self.extra_sections.update(set(sections))
-
- if is_dict_option:
- base = option_obj
- else:
- base = option_obj.item
-
- for name in sections:
- nested = base.get_extra_sections(name, self)
- self.extra_sections.update(set(nested))
-
try:
value = option_obj.parse(value, **kwargs)
except ValueError, e:
=== modified file 'configglue/schema.py'
--- configglue/schema.py 2011-07-23 21:11:55 +0000
+++ configglue/schema.py 2011-07-29 21:33:28 +0000
@@ -14,6 +14,7 @@
#
###############################################################################
+import json
from ConfigParser import (
NoSectionError,
NoOptionError,
@@ -578,7 +579,7 @@
def __init__(self, name='', spec=None, strict=False, raw=False,
default=NO_DEFAULT, fatal=False, help='', action='store',
- item=None, short_name=''):
+ item=None, short_name='', json=True):
if spec is None:
spec = {}
if item is None:
@@ -586,6 +587,7 @@
self.spec = spec
self.strict = strict
self.item = item
+ self.json = json
super(DictOption, self).__init__(name=name, raw=raw,
default=default, fatal=fatal, help=help, action=action,
short_name=short_name)
@@ -606,21 +608,37 @@
default[key] = value.default
return default
- def parse(self, section, parser=None, raw=False):
+ def parse(self, value, parser, raw=False):
"""Parse the given value.
A *parser* object is used to parse individual dict items.
If *raw* is *True*, return the value unparsed.
"""
- parsed = dict(parser.items(section))
+ is_json = self.json
+ if is_json:
+ try:
+ parsed = json.loads(value)
+ is_json = isinstance(parsed, dict)
+ except Exception:
+ is_json = False
+
+ if not is_json:
+ # process extra sections
+ sections = value.split()
+ parser.extra_sections.update(set(sections))
+ for name in sections:
+ nested = self.get_extra_sections(name, parser)
+ parser.extra_sections.update(set(nested))
+
+ parsed = dict(parser.items(value))
+
result = {}
-
# parse config items according to spec
for key, value in parsed.items():
if self.strict and not key in self.spec:
- raise ValueError("Invalid key %s in section %s" % (key,
- section))
+ raise ValueError("Invalid key %s in section %s" % (
+ key, value))
option = self.spec.get(key, None)
if option is None:
# option not part of spec, but we are in non-strict mode
@@ -641,7 +659,7 @@
option = self.spec[key]
if option.fatal:
raise ValueError("No option '%s' in section '%s'" %
- (key, section))
+ (key, value))
else:
if not raw:
value = option.default
=== modified file 'configglue/tests/test_schema.py'
--- configglue/tests/test_schema.py 2011-07-23 21:11:55 +0000
+++ configglue/tests/test_schema.py 2011-07-29 21:33:28 +0000
@@ -15,8 +15,12 @@
#
###############################################################################
+import textwrap
import unittest
-from ConfigParser import NoOptionError
+from ConfigParser import (
+ NoOptionError,
+ NoSectionError,
+)
from StringIO import StringIO
from configglue.parser import (
@@ -737,6 +741,116 @@
parser.readfp(config)
self.assertEqual(parser.values(), expected_values)
+ def test_parse_dict_no_json(self):
+ """Test DictOption parse a dict when json is disabled."""
+ class MySchema(Schema):
+ foo = self.cls(spec={
+ 'bar': StringOption(),
+ 'baz': IntOption(),
+ 'bla': BoolOption(),
+ }, json=False)
+
+ config = StringIO("""[__main__]
+foo = mydict
+[mydict]
+bar=baz
+baz=42
+bla=Yes
+""")
+ expected_values = {
+ '__main__': {
+ 'foo': {'bar': 'baz', 'baz': 42, 'bla': True}}}
+
+ schema = MySchema()
+ parser = SchemaConfigParser(schema)
+ parser.readfp(config)
+ self.assertEqual(parser.values(), expected_values)
+
+ def test_parse_dict_json(self):
+ """Test DictOption parse a json dict."""
+ class MySchema(Schema):
+ foo = self.cls(spec={
+ 'bar': StringOption(),
+ 'baz': IntOption(),
+ 'bla': BoolOption(),
+ })
+
+ config = StringIO(textwrap.dedent("""
+ [__main__]
+ foo = {
+ "bar": "baz",
+ "baz": "42",
+ "bla": "Yes"}
+ """))
+ expected_values = {
+ '__main__': {
+ 'foo': {'bar': 'baz', 'baz': 42, 'bla': True}}}
+
+ schema = MySchema()
+ parser = SchemaConfigParser(schema)
+ parser.readfp(config)
+ self.assertEqual(parser.values(), expected_values)
+
+ def test_parse_dict_json_invalid_json(self):
+ """Test DictOption parse invalid json."""
+ class MySchema(Schema):
+ foo = self.cls(spec={
+ 'bar': StringOption(),
+ 'baz': IntOption(),
+ 'bla': BoolOption(),
+ })
+
+ config = StringIO(textwrap.dedent("""
+ [__main__]
+ foo = {'bar': 23}
+ """))
+
+ schema = MySchema()
+ parser = SchemaConfigParser(schema)
+ parser.readfp(config)
+ self.assertRaises(NoSectionError, parser.values)
+
+ def test_parse_dict_json_non_dict_json(self):
+ """Test DictOption parse json not representing a dict."""
+ class MySchema(Schema):
+ foo = self.cls(spec={
+ 'bar': StringOption(),
+ 'baz': IntOption(),
+ 'bla': BoolOption(),
+ })
+
+ config = StringIO(textwrap.dedent("""
+ [__main__]
+ foo = [1, 2, 3]
+ """))
+
+ schema = MySchema()
+ parser = SchemaConfigParser(schema)
+ parser.readfp(config)
+ self.assertRaises(NoSectionError, parser.values)
+
+ def test_parse_dict_no_json_with_json(self):
+ """Test DictOption parse json when json is disabled."""
+ class MySchema(Schema):
+ foo = self.cls(spec={
+ 'bar': StringOption(),
+ 'baz': IntOption(),
+ 'bla': BoolOption(),
+ }, json=False)
+
+ config = StringIO(textwrap.dedent("""
+ [__main__]
+ foo = {
+ "bar": "baz",
+ "baz": "42",
+ "bla": "Yes"}
+ """))
+
+ schema = MySchema()
+ parser = SchemaConfigParser(schema)
+ parser.readfp(config)
+ self.assertRaises(NoSectionError, parser.values)
+
def test_parse_raw(self):
"""Test DictOption parse using raw=True."""
class MySchema(Schema):
Follow ups