Mercurial > nagslang
annotate nagslang/yamlish.py @ 408:d04981e24fda
Move hard-coded starting point to levels meta file
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Sat, 07 Sep 2013 12:32:40 +0200 |
parents | a106d7e1415b |
children | 80c452f348dc |
rev | line source |
---|---|
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
1 ''' |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
2 Serializer and dumper for a simple, YAMLish format (actually a YAML subset). |
129
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
3 The top level object is a dict or list. |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
4 lists and dicts can contain: |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
5 * lists, dicts, |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
6 * single line strings, |
120
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
7 * ints, floats, |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
8 * True, False, and None |
136
0280ee006d95
Support integer dict keys
Stefano Rivera <stefano@rivera.za.net>
parents:
132
diff
changeset
|
9 dict keys can only be scalar. |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
10 ''' |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
11 |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
12 import re |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
13 |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
14 |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
15 def dump(data, file_object): |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
16 file_object.write(dump_s(data)) |
90
a8d83de5b460
Dump our YAML subset too
Stefano Rivera <stefano@rivera.za.net>
parents:
89
diff
changeset
|
17 |
a8d83de5b460
Dump our YAML subset too
Stefano Rivera <stefano@rivera.za.net>
parents:
89
diff
changeset
|
18 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
19 def dump_s(data): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
20 return Dumper().dump(data) |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
21 |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
22 |
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
23 def load(file_object): |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
24 yaml = file_object.read() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
25 return load_s(yaml) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
26 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
27 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
28 def load_s(yaml): |
112
c28f2fc2bb05
Test with dump_s and load_s
Stefano Rivera <stefano@rivera.za.net>
parents:
111
diff
changeset
|
29 return Parser().parse(yaml.strip()) |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
30 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
31 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
32 class Dumper(object): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
33 def dump(self, data): |
141
076448ba0582
Add a trailing newline
Stefano Rivera <stefano@rivera.za.net>
parents:
138
diff
changeset
|
34 return '\n'.join(self._dump_block(data)) + '\n' |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
35 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
36 def _dump_block(self, data, indent=0): |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
37 for type_ in (list, tuple, dict): |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
38 if isinstance(data, type_): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
39 f = getattr(self, '_dump_%s_block' % type_.__name__) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
40 return f(data, indent) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
41 raise NotImplementedError() |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
42 |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
43 def _dump_inline(self, data): |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
44 if data is True or data is False or data is None: |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
45 return self._dump_literal(data) |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
46 for type_ in (list, tuple, dict, basestring, int, float): |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
47 if isinstance(data, type_): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
48 f = getattr(self, '_dump_%s' % type_.__name__) |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
49 return f(data) |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
50 raise NotImplementedError() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
51 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
52 def _dump_list_block(self, data, indent): |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
53 output = [] |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
54 for item in data: |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
55 if self._inlineable(item): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
56 output.append('%s- %s' % (' ' * indent, |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
57 self._dump_inline(item))) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
58 else: |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
59 dumped = self._dump_block(item, indent + 2) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
60 dumped[0] = '%s- %s' % (' ' * indent, dumped[0][indent + 2:]) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
61 output += dumped |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
62 return output |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
63 |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
64 _dump_tuple_block = _dump_list_block |
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
65 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
66 def _dump_dict_block(self, data, indent): |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
67 output = [] |
121
7d022648aa4e
Dump dicts in sorted order
Stefano Rivera <stefano@rivera.za.net>
parents:
120
diff
changeset
|
68 for k, v in sorted(data.iteritems()): |
137
c5ff16c66100
Support other interesting keys, too
Stefano Rivera <stefano@rivera.za.net>
parents:
136
diff
changeset
|
69 output.append('%s%s:' % (' ' * indent, self._dump_inline(k))) |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
70 if self._inlineable(v): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
71 output[-1] += ' ' + self._dump_inline(v) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
72 elif isinstance(v, dict): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
73 output += self._dump_block(v, indent + 2) |
344
1d73867becbe
Allow tuples in dicts
Stefano Rivera <stefano@rivera.za.net>
parents:
141
diff
changeset
|
74 elif isinstance(v, (list, tuple)): |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
75 output += self._dump_block(v, indent) |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
76 else: |
344
1d73867becbe
Allow tuples in dicts
Stefano Rivera <stefano@rivera.za.net>
parents:
141
diff
changeset
|
77 raise NotImplementedError("Cannot dump %r", data) |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
78 return output |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
79 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
80 def _inlineable(self, data): |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
81 if isinstance(data, (list, tuple)): |
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
82 return all(not isinstance(item, (list, dict, tuple)) |
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
83 for item in data) |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
84 elif isinstance(data, dict): |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
85 return all(not isinstance(item, (list, dict, tuple)) |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
86 for item in data.itervalues()) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
87 else: |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
88 return True |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
89 |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
90 def _dump_list(self, data): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
91 return '[%s]' % ', '.join(self._dump_inline(item) for item in data) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
92 |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
93 _dump_tuple = _dump_list |
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
94 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
95 def _dump_dict(self, data): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
96 return '{%s}' % ', '.join( |
138
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
97 '%s: %s' % (self._dump_inline(key), self._dump_inline(value)) |
366b334a7018
Render tuples to lists
Stefano Rivera <stefano@rivera.za.net>
parents:
137
diff
changeset
|
98 for key, value in data.iteritems()) |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
99 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
100 def _dump_basestring(self, data): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
101 if data in ('true', 'false', 'null'): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
102 return "'%s'" % data |
380
a106d7e1415b
Colons are allowed in strings
Stefano Rivera <stefano@rivera.za.net>
parents:
344
diff
changeset
|
103 if "'" in data or ':' in data or data.startswith('['): |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
104 return "'%s'" % data.replace("'", "''") |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
105 if data == '': |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
106 return "''" |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
107 return data |
120
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
108 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
109 def _dump_int(self, data): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
110 return str(data) |
120
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
111 |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
112 def _dump_float(self, data): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
113 return str(data) |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
114 |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
115 def _dump_literal(self, data): |
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
116 return { |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
117 True: 'true', |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
118 False: 'false', |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
119 None: 'null', |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
120 }[data] |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
121 |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
122 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
123 class Parser(object): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
124 _spaces_re = re.compile(r'^(\s*)(.*)') |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
125 _list_re = re.compile(r'^(-\s+)(.*)') |
380
a106d7e1415b
Colons are allowed in strings
Stefano Rivera <stefano@rivera.za.net>
parents:
344
diff
changeset
|
126 _dict_re = re.compile(r"^((?![{['])[^-:]+):\s?(.*)") |
132 | 127 _inline_list_re = re.compile(r"^([^',]+|(?:'')+|'.+?[^'](?:'')*')" |
128 r"(?:, (.*))?$") | |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
129 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
130 def __init__(self): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
131 # Stack of (indent level, container object) |
129
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
132 self._stack = [] |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
133 # When a dict's value is a nested block, remember the key |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
134 self._parent_key = None |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
135 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
136 @property |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
137 def _indent(self): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
138 return self._stack[-1][0] |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
139 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
140 @property |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
141 def _container(self): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
142 return self._stack[-1][1] |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
143 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
144 @property |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
145 def _in_list(self): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
146 return isinstance(self._container, list) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
147 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
148 @property |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
149 def _in_dict(self): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
150 return isinstance(self._container, dict) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
151 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
152 def _push(self, container, indent=None): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
153 in_list = self._in_list |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
154 assert in_list or self._parent_key |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
155 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
156 if indent is None: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
157 indent = self._indent |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
158 self._stack.append((indent, container())) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
159 if in_list: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
160 self._stack[-2][1].append(self._container) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
161 else: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
162 self._stack[-2][1][self._parent_key] = self._container |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
163 self._parent_key = None |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
164 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
165 def parse(self, yaml): |
129
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
166 if yaml.startswith(('[', '{')): |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
167 return self._parse_value(yaml) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
168 |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
169 if yaml.startswith('-'): |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
170 self._stack.append((0, [])) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
171 else: |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
172 self._stack.append((0, {})) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
173 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
174 for line in yaml.splitlines(): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
175 spaces, line = self._spaces_re.match(line).groups() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
176 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
177 while len(spaces) < self._indent: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
178 self._stack.pop() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
179 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
180 lm = self._list_re.match(line) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
181 dm = self._dict_re.match(line) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
182 if len(spaces) == self._indent: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
183 if lm and self._in_dict: |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
184 # Starting a list in a dict |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
185 self._push(list) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
186 elif dm and self._in_list: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
187 # Left an embedded list |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
188 self._stack.pop() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
189 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
190 if len(spaces) > self._indent: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
191 assert self._parent_key |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
192 if dm: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
193 # Nested dict |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
194 self._push(dict, len(spaces)) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
195 elif lm: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
196 # Over-indented list in a dict |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
197 self._push(list, len(spaces)) |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
198 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
199 indent = self._indent |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
200 while lm and lm.group(2).startswith('- '): |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
201 # Nested lists |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
202 prefix, line = lm.groups() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
203 indent += len(prefix) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
204 self._push(list, indent) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
205 lm = self._list_re.match(line) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
206 del indent |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
207 |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
208 if lm: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
209 prefix, line = lm.groups() |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
210 dm = self._dict_re.match(line) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
211 if dm: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
212 self._push(dict, self._indent + len(prefix)) |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
213 else: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
214 assert self._in_list |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
215 self._container.append(self._parse_value(line)) |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
216 |
103
adf3cd83bf7a
Support a common stylistic variation
Stefano Rivera <stefano@rivera.za.net>
parents:
90
diff
changeset
|
217 if dm: |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
218 key, value = dm.groups() |
136
0280ee006d95
Support integer dict keys
Stefano Rivera <stefano@rivera.za.net>
parents:
132
diff
changeset
|
219 key = self._parse_value(key) |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
220 assert self._in_dict |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
221 if value: |
136
0280ee006d95
Support integer dict keys
Stefano Rivera <stefano@rivera.za.net>
parents:
132
diff
changeset
|
222 value = self._parse_value(value) |
0280ee006d95
Support integer dict keys
Stefano Rivera <stefano@rivera.za.net>
parents:
132
diff
changeset
|
223 self._container[key] = value |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
224 else: |
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
225 self._parent_key = key |
89
102043902451
Simple (subset of) YAML parser
Stefano Rivera <stefano@rivera.za.net>
parents:
diff
changeset
|
226 |
111
16d9f3a0dc29
Refactored as classes for readability and to make it easier to support more types
Stefano Rivera <stefano@rivera.za.net>
parents:
103
diff
changeset
|
227 return self._stack[0][1] |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
228 |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
229 def _parse_value(self, value): |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
230 if value.startswith("'") and value.endswith("'"): |
130
67f18e72024d
Handle corner cases around quotes in strings
Stefano Rivera <stefano@rivera.za.net>
parents:
129
diff
changeset
|
231 return value[1:-1].replace("''", "'") |
129
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
232 if value.startswith('[') and value.endswith(']'): |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
233 value = value[1:-1] |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
234 output = [] |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
235 while value: |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
236 m = self._inline_list_re.match(value) |
130
67f18e72024d
Handle corner cases around quotes in strings
Stefano Rivera <stefano@rivera.za.net>
parents:
129
diff
changeset
|
237 assert m, value |
129
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
238 output.append(self._parse_value(m.group(1))) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
239 value = m.group(2) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
240 return output |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
241 if value.startswith('{') and value.endswith('}'): |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
242 value = value[1:-1] |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
243 output = {} |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
244 while value: |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
245 key, value = value.split(': ', 1) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
246 m = self._inline_list_re.match(value) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
247 assert m |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
248 output[key] = self._parse_value(m.group(1)) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
249 value = m.group(2) |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
250 return output |
423266f0b9e4
Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents:
121
diff
changeset
|
251 if value.startswith('!!'): |
131
568476db7115
Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents:
130
diff
changeset
|
252 raise NotImplementedError() |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
253 if value == 'true': |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
254 return True |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
255 if value == 'false': |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
256 return False |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
257 if value == 'null': |
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
258 return None |
120
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
259 for type_ in (int, float): |
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
260 try: |
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
261 return type_(value) |
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
262 except ValueError: |
e6e7a471146a
Support numeric types
Stefano Rivera <stefano@rivera.za.net>
parents:
119
diff
changeset
|
263 pass |
119
b75de48a618c
Support boolean and None types
Stefano Rivera <stefano@rivera.za.net>
parents:
113
diff
changeset
|
264 return value |