annotate nagslang/yamlish.py @ 344:1d73867becbe

Allow tuples in dicts
author Stefano Rivera <stefano@rivera.za.net>
date Fri, 06 Sep 2013 13:38:07 +0200
parents 076448ba0582
children a106d7e1415b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
568476db7115 Dump inline lists and dicts too
Stefano Rivera <stefano@rivera.za.net>
parents: 130
diff changeset
103 if "'" in data:
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+)(.*)')
129
423266f0b9e4 Support inline lists, dicts, etc. And alternative top level objects
Stefano Rivera <stefano@rivera.za.net>
parents: 121
diff changeset
126 _dict_re = re.compile(r'^((?![{[])[^-:]+):\s?(.*)')
132
e1ef3727b7f8 Wrap long line
Stefano Rivera <stefano@rivera.za.net>
parents: 131
diff changeset
127 _inline_list_re = re.compile(r"^([^',]+|(?:'')+|'.+?[^'](?:'')*')"
e1ef3727b7f8 Wrap long line
Stefano Rivera <stefano@rivera.za.net>
parents: 131
diff changeset
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