Mercurial > nagslang
changeset 129:423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Mon, 02 Sep 2013 16:57:59 +0200 |
parents | fbb073720bac |
children | 67f18e72024d |
files | nagslang/tests/test_yamlish.py nagslang/yamlish.py |
diffstat | 2 files changed, 52 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/nagslang/tests/test_yamlish.py Mon Sep 02 17:23:13 2013 +0200 +++ b/nagslang/tests/test_yamlish.py Mon Sep 02 16:57:59 2013 +0200 @@ -48,6 +48,9 @@ def test_simple_dict(self): self.roundtrip({'foo': 'bar'}) + def test_simple_list(self): + self.roundtrip(['foo', 'bar']) + def test_dict_of_dicts(self): self.roundtrip({'foo': {'bar': 'baz'}}) @@ -61,11 +64,20 @@ } }) + def test_list_of_lists(self): + self.roundtrip(['foo', ['bar', 'baz'], 'qux']) + def test_dict_list(self): self.roundtrip({ 'foo': ['bar', 'baz'], }) + def test_list_dict(self): + self.roundtrip([ + {'foo': 'bar'}, + {'baz': 'qux', 'quux': 'corge'}, + ]) + def test_nested_lists(self): self.roundtrip({ 'foo': [['bar', 'baz', 'qux'], 'quux'], @@ -97,6 +109,13 @@ return yaml.dump(data, default_flow_style=False) +class TestFromPyYAMLInlineLists(TestRoundTrip): + def dump_s(self, data): + if yaml is None: + raise SkipTest('yaml module unavailable') + return yaml.dump(data) + + class TestToPyYAML(TestRoundTrip): def load_s(self, text): if yaml is None:
--- a/nagslang/yamlish.py Mon Sep 02 17:23:13 2013 +0200 +++ b/nagslang/yamlish.py Mon Sep 02 16:57:59 2013 +0200 @@ -1,6 +1,6 @@ ''' Serializer and dumper for a simple, YAMLish format (actually a YAML subset). -The top level object is a dict. +The top level object is a dict or list. lists and dicts can contain: * lists, dicts, * single line strings, @@ -86,11 +86,12 @@ class Parser(object): _spaces_re = re.compile(r'^(\s*)(.*)') _list_re = re.compile(r'^(-\s+)(.*)') - _dict_re = re.compile(r'^([^-:]+):\s?(.*)') + _dict_re = re.compile(r'^((?![{[])[^-:]+):\s?(.*)') + _inline_list_re = re.compile(r"^([^',]+|''|'.+?[^'](?:'')*')(?:, (.*))?$") def __init__(self): # Stack of (indent level, container object) - self._stack = [(0, {})] + self._stack = [] # When a dict's value is a nested block, remember the key self._parent_key = None @@ -124,6 +125,14 @@ self._parent_key = None def parse(self, yaml): + if yaml.startswith(('[', '{')): + return self._parse_value(yaml) + + if yaml.startswith('-'): + self._stack.append((0, [])) + else: + self._stack.append((0, {})) + for line in yaml.splitlines(): spaces, line = self._spaces_re.match(line).groups() @@ -180,6 +189,27 @@ def _parse_value(self, value): if value.startswith("'") and value.endswith("'"): return value[1:-1] + if value.startswith('[') and value.endswith(']'): + value = value[1:-1] + output = [] + while value: + m = self._inline_list_re.match(value) + assert m + output.append(self._parse_value(m.group(1))) + value = m.group(2) + return output + if value.startswith('{') and value.endswith('}'): + value = value[1:-1] + output = {} + while value: + key, value = value.split(': ', 1) + m = self._inline_list_re.match(value) + assert m + output[key] = self._parse_value(m.group(1)) + value = m.group(2) + return output + if value.startswith('!!'): + raise NotImplemented() if value == 'true': return True if value == 'false':