← Back to team overview

configglue team mailing list archive

[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