Mercurial > nagslang
changeset 102:fd9c4db5ddfe
Rename to yamlish
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Mon, 02 Sep 2013 11:56:08 +0200 |
parents | 93aa745d57ff |
children | adf3cd83bf7a |
files | nagslang/level_serializer.py nagslang/tests/test_level_serializer.py nagslang/tests/test_yamlish.py nagslang/yamlish.py |
diffstat | 4 files changed, 168 insertions(+), 168 deletions(-) [+] |
line wrap: on
line diff
--- a/nagslang/level_serializer.py Mon Sep 02 12:45:06 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -''' -Serializer and dumper for a simple, YAMLish format (actually a YAML subset). -The top level object is a dict. -lists and dicts can contain lists, dicts, and strings. -''' - -import re - - -def dump(data, file_object): - file_object.write('\n'.join(_dump(data, 0))) - - -def _dump(obj, indent): - if isinstance(obj, list): - for item in obj: - yield '%s- %s' % (' ' * indent, - '\n'.join(_dump(item, indent + 2)).strip()) - elif isinstance(obj, dict): - for k, v in obj.iteritems(): - if isinstance(v, basestring): - yield '%s%s: %s' % (' ' * indent, k, v) - else: - extra = 0 if isinstance(v, list) else 2 - yield '%s%s:\n%s' % (' ' * indent, k, - '\n'.join(_dump(v, indent + extra))) - elif isinstance(obj, basestring): - yield '%s%s' % (' ' * indent, obj) - - -spaces_re = re.compile(r'^(\s*)(.*)') -list_re = re.compile(r'^(-\s+)(.*)') -dict_re = re.compile(r'^([^-:]+):\s?(.*)') - - -def load(file_object): - # Stack of (indent level, container object) - stack = [(0, {})] - indent = lambda: stack[-1][0] - obj = lambda: stack[-1][1] - - # When a dict's value is a nested block, remember the key - parent_key = None - - for line in file_object: - spaces, line = spaces_re.match(line).groups() - - while len(spaces) < indent(): - stack.pop() - - lm = list_re.match(line) - dm = dict_re.match(line) - if len(spaces) == indent(): - if lm: - assert isinstance(obj(), list) or parent_key - if isinstance(obj(), dict) and parent_key: - # Starting a list in a dict - stack.append((indent(), [])) - stack[-2][1][parent_key] = obj() - parent_key = None - elif dm and isinstance(obj(), list): - # Left an embedded list - stack.pop() - - if len(spaces) > indent(): - # Nested dict - assert dm - assert parent_key - stack.append((len(spaces), {})) - stack[-2][1][parent_key] = obj() - parent_key = None - - while lm and lm.group(2).startswith('- '): - # Nested lists - prefix, line = lm.groups() - stack.append((indent() + len(prefix), [])) - stack[-2][1].append(obj()) - lm = list_re.match(line) - - if lm: - prefix, line = lm.groups() - dm = dict_re.match(line) - if dm: - stack.append((indent() + len(prefix), {})) - stack[-2][1].append(obj()) - else: - obj().append(line) - - if dm: - key, value = dm.groups() - if value: - obj()[key] = value - else: - parent_key = key - - return stack[0][1]
--- a/nagslang/tests/test_level_serializer.py Mon Sep 02 12:45:06 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -from unittest import TestCase, SkipTest -from StringIO import StringIO - -try: - import yaml -except ImportError: - yaml = None # pyflakes:ignore - -from nagslang.level_serializer import load, dump - - -class TestRoundTrip(TestCase): - def roundtrip(self, data): - f = StringIO() - self.dump(data, f) - f.seek(0) - print '\n=== Begin ===\n%s\n=== End ===' % f.buf.rstrip() - self.assertEqual(self.load(f), data) - - def dump(self, data, f): - dump(data, f) - - def load(self, f): - return load(f) - - def test_simple_dict(self): - self.roundtrip({'foo': 'bar'}) - - def test_dict_of_dicts(self): - self.roundtrip({'foo': {'bar': 'baz'}}) - - def test_dict_tree(self): - self.roundtrip({ - 'foo': { - 'bar': { - 'baz': 'qux' - }, - 'quux': 'corge', - } - }) - - def test_dict_list(self): - self.roundtrip({ - 'foo': ['bar', 'baz'], - }) - - def test_nested_lists(self): - self.roundtrip({ - 'foo': [['bar', 'baz', 'qux'], 'quux'], - }) - - def test_list_of_dicts(self): - self.roundtrip({ - 'foo': [ - {'bar': 'baz'}, - {'qux': 'quux'}, - ], - }) - - -class TestFromPyYAML(TestRoundTrip): - def dump(self, data, f): - if yaml is None: - raise SkipTest('yaml module unavailable') - yaml.dump(data, f, default_flow_style=False) - - -class TestToPyYAML(TestRoundTrip): - def load(self, f): - if yaml is None: - raise SkipTest('yaml module unavailable') - return yaml.load(f)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nagslang/tests/test_yamlish.py Mon Sep 02 11:56:08 2013 +0200 @@ -0,0 +1,72 @@ +from unittest import TestCase, SkipTest +from StringIO import StringIO + +try: + import yaml +except ImportError: + yaml = None # pyflakes:ignore + +from nagslang.yamlish import load, dump + + +class TestRoundTrip(TestCase): + def roundtrip(self, data): + f = StringIO() + self.dump(data, f) + f.seek(0) + print '\n=== Begin ===\n%s\n=== End ===' % f.buf.rstrip() + self.assertEqual(self.load(f), data) + + def dump(self, data, f): + dump(data, f) + + def load(self, f): + return load(f) + + def test_simple_dict(self): + self.roundtrip({'foo': 'bar'}) + + def test_dict_of_dicts(self): + self.roundtrip({'foo': {'bar': 'baz'}}) + + def test_dict_tree(self): + self.roundtrip({ + 'foo': { + 'bar': { + 'baz': 'qux' + }, + 'quux': 'corge', + } + }) + + def test_dict_list(self): + self.roundtrip({ + 'foo': ['bar', 'baz'], + }) + + def test_nested_lists(self): + self.roundtrip({ + 'foo': [['bar', 'baz', 'qux'], 'quux'], + }) + + def test_list_of_dicts(self): + self.roundtrip({ + 'foo': [ + {'bar': 'baz'}, + {'qux': 'quux'}, + ], + }) + + +class TestFromPyYAML(TestRoundTrip): + def dump(self, data, f): + if yaml is None: + raise SkipTest('yaml module unavailable') + yaml.dump(data, f, default_flow_style=False) + + +class TestToPyYAML(TestRoundTrip): + def load(self, f): + if yaml is None: + raise SkipTest('yaml module unavailable') + return yaml.load(f)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nagslang/yamlish.py Mon Sep 02 11:56:08 2013 +0200 @@ -0,0 +1,96 @@ +''' +Serializer and dumper for a simple, YAMLish format (actually a YAML subset). +The top level object is a dict. +lists and dicts can contain lists, dicts, and strings. +''' + +import re + + +def dump(data, file_object): + file_object.write('\n'.join(_dump(data, 0))) + + +def _dump(obj, indent): + if isinstance(obj, list): + for item in obj: + yield '%s- %s' % (' ' * indent, + '\n'.join(_dump(item, indent + 2)).strip()) + elif isinstance(obj, dict): + for k, v in obj.iteritems(): + if isinstance(v, basestring): + yield '%s%s: %s' % (' ' * indent, k, v) + else: + extra = 0 if isinstance(v, list) else 2 + yield '%s%s:\n%s' % (' ' * indent, k, + '\n'.join(_dump(v, indent + extra))) + elif isinstance(obj, basestring): + yield '%s%s' % (' ' * indent, obj) + + +spaces_re = re.compile(r'^(\s*)(.*)') +list_re = re.compile(r'^(-\s+)(.*)') +dict_re = re.compile(r'^([^-:]+):\s?(.*)') + + +def load(file_object): + # Stack of (indent level, container object) + stack = [(0, {})] + indent = lambda: stack[-1][0] + obj = lambda: stack[-1][1] + + # When a dict's value is a nested block, remember the key + parent_key = None + + for line in file_object: + spaces, line = spaces_re.match(line).groups() + + while len(spaces) < indent(): + stack.pop() + + lm = list_re.match(line) + dm = dict_re.match(line) + if len(spaces) == indent(): + if lm: + assert isinstance(obj(), list) or parent_key + if isinstance(obj(), dict) and parent_key: + # Starting a list in a dict + stack.append((indent(), [])) + stack[-2][1][parent_key] = obj() + parent_key = None + elif dm and isinstance(obj(), list): + # Left an embedded list + stack.pop() + + if len(spaces) > indent(): + # Nested dict + assert dm + assert parent_key + stack.append((len(spaces), {})) + stack[-2][1][parent_key] = obj() + parent_key = None + + while lm and lm.group(2).startswith('- '): + # Nested lists + prefix, line = lm.groups() + stack.append((indent() + len(prefix), [])) + stack[-2][1].append(obj()) + lm = list_re.match(line) + + if lm: + prefix, line = lm.groups() + dm = dict_re.match(line) + if dm: + stack.append((indent() + len(prefix), {})) + stack[-2][1].append(obj()) + else: + obj().append(line) + + if dm: + key, value = dm.groups() + if value: + obj()[key] = value + else: + parent_key = key + + return stack[0][1]