| Index: chainedconfigparser.py |
| diff --git a/chainedconfigparser.py b/chainedconfigparser.py |
| index ce26b04b50e175e1cbd99a772f2a589acd1ac64c..9691174ae5853a28b9f06402f2003b79447599a0 100644 |
| --- a/chainedconfigparser.py |
| +++ b/chainedconfigparser.py |
| @@ -6,6 +6,7 @@ import os |
| import io |
| import ConfigParser |
| from StringIO import StringIO |
| +from collections import OrderedDict |
| class Item(tuple): |
| @@ -157,6 +158,79 @@ class ChainedConfigParser(ConfigParser.SafeConfigParser): |
| raise ConfigParser.NoSectionError(section) |
| raise ConfigParser.NoOptionError(option, section) |
| + def as_json_object(self, section): |
|
Sebastian Noack
2018/04/14 00:33:07
Actually there isn't anything specific to JSON in
tlucas
2018/04/14 08:36:23
You are right - what would you suggest? How about
Sebastian Noack
2018/04/14 08:54:26
Maybe section_as_dict()?
tlucas
2018/04/18 14:46:04
Done.
|
| + r"""Parse a given section into a JSON object. |
| + |
| + Parse arbitrary key/value pairs from 'section' of the current |
| + configuration into a nested JSON object. |
| + |
| + The following rules need to be considered: |
| + |
| + * An option's key may be declared as a series of nested dictionary keys, |
| + seperated by '.'. |
| + * An option's key must end with '[]', to mark this option as an array |
|
Sebastian Noack
2018/04/14 00:33:06
Nit: Please make all bullet point end with punctat
Sebastian Noack
2018/04/14 00:33:07
I just noticed, we could identify arrays by the pr
tlucas
2018/04/14 08:36:23
The bullet points: ack
The newlines: Nice idea, w
tlucas
2018/04/18 14:46:04
Done.
|
| + * When an option is marked as an array, no other nested objects may |
| + follow |
| + * An array is expandable by the ConfigParser's '+=' token. |
| + * Values may be marked as `number` or `bool` by prefixing them |
| + accordingly: |
| + * bool:<value> |
| + * number:<value> |
| + |
| + Example: |
| + |
| + { |
| + "good": false, |
| + "bar": { |
| + "baz": ["bar", "bazinga"] |
| + foo = foo }, |
| + bar.baz[] = bar "is": { |
| + baz.foo = a "integer": 1, |
| + baz.z[] = b bool:true "float": 1.4 |
| + bar.baz[] += bazinga ==> }, |
| + bad = bool:true "baz": { |
| + good = bool:false "foo": "a", |
| + is.integer = number:1 "z": ["b", true] |
| + is.float = number:1.4 }, |
| + "bad": true |
| + "foo": "foo" |
| + } |
| + """ |
| + def parse_values(v): |
| + if isinstance(v, list): |
| + return [parse_values(x) for x in v] |
| + |
| + if v.startswith('number:'): |
| + v = v.split(':', 1)[1] |
| + try: |
| + v = int(v) |
| + except ValueError: |
| + v = float(v) |
| + elif v == 'bool:true': |
| + v = True |
| + elif v == 'bool:false': |
| + v = False |
| + return v |
| + |
| + def setdefault_recursive(target, arr): |
| + if len(arr) == 2: |
| + target.setdefault(arr[0], parse_values(arr[1])) |
| + else: |
| + current = target.setdefault(arr[0], OrderedDict()) |
| + setdefault_recursive(current, arr[1:]) |
| + |
| + data = self.items(section) |
| + result = OrderedDict() |
| + |
| + for k, v in data: |
| + if k.endswith('[]'): |
| + k = k[:-2] |
| + v = v.split() |
|
Sebastian Noack
2018/04/14 00:33:06
We might want to strip by newlines, so that array
tlucas
2018/04/14 08:36:23
Acknowledged.
tlucas
2018/04/18 14:46:04
Done.
|
| + |
| + setdefault_recursive(result, k.split('.') + [v]) |
|
Sebastian Noack
2018/04/14 00:33:06
It seems weird/unnecessary to merge the key segmen
tlucas
2018/04/14 08:36:23
Not at all, will change.
tlucas
2018/04/18 14:46:04
Done.
|
| + |
| + return result |
| + |
| def readfp(self, fp, filename=None): |
| raise NotImplementedError |