1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
# Copyright (C) 2013 Codethink Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import morphlib
from morphlib.util import OrderedDict
if morphlib.got_yaml: # pragma: no cover
yaml = morphlib.yaml
if morphlib.got_yaml: # pragma: no cover
class OrderedDictYAMLLoader(yaml.SafeLoader):
"""A YAML loader that loads mappings into ordered dictionaries.
When YAML is loaded with this Loader, it loads mappings as ordered
dictionaries, so the order the keys were written in is maintained.
When combined with the OrderedDictYAMLDumper, this allows yaml documents
to be written out in a similar format to they were read.
"""
def __init__(self, *args, **kwargs):
yaml.SafeLoader.__init__(self, *args, **kwargs)
# When YAML encounters a mapping (which YAML identifies with
# the given tag), it will use construct_yaml_map to read it as
# an OrderedDict.
self.add_constructor(u'tag:yaml.org,2002:map',
type(self).construct_yaml_map)
def construct_yaml_map(self, node):
data = OrderedDict()
yield data
value = self.construct_mapping(node)
data.update(value)
def construct_mapping(self, node, deep=False):
if isinstance(node, yaml.MappingNode):
self.flatten_mapping(node)
else:
raise yaml.constructor.ConstructorError(
None, None,
'expected a mapping node, but found %s' % node.id,
node.start_mark)
mapping = OrderedDict()
for key_node, value_node in node.value:
key = self.construct_object(key_node, deep=deep)
try:
hash(key)
except TypeError, exc:
raise yaml.constructor.ConstructorError(
'while constructing a mapping', node.start_mark,
'found unacceptable key (%s)' % exc,
key_node.start_mark)
value = self.construct_object(value_node, deep=deep)
mapping[key] = value
return mapping
class OrderedDictYAMLDumper(yaml.SafeDumper):
"""A YAML dumper that will dump OrderedDicts as mappings.
When YAML is dumped with this Dumper, it dumps OrderedDicts as
mappings, preserving the key order, so the order the keys were
written in is maintained.
When combined with the OrderedDictYAMLDumper, this allows yaml documents
to be written out in a similar format to they were read.
"""
def __init__(self, *args, **kwargs):
yaml.SafeDumper.__init__(self, *args, **kwargs)
# When YAML sees an OrderedDict, use represent_ordered_dict to
# dump it
self.add_representer(OrderedDict,
type(self).represent_ordered_dict)
def represent_ordered_dict(self, odict):
return self.represent_ordered_mapping(
u'tag:yaml.org,2002:map', odict)
def represent_ordered_mapping(self, tag, omap):
value = []
node = yaml.MappingNode(tag, value)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
best_style = True
for item_key, item_value in omap.iteritems():
node_key = self.represent_data(item_key)
node_value = self.represent_data(item_value)
if not (isinstance(node_key, yaml.ScalarNode) and
not node_key.style):
best_style = False # pragma: no cover
if not (isinstance(node_value, yaml.ScalarNode) and
not node_value.style):
best_style = False # pragma: no cover
value.append((node_key, node_value))
if self.default_flow_style is not None:
node.flow_style = self.default_flow_style
else:
node.flow_style = best_style # pragma: no cover
return node
def load(*args, **kwargs):
return yaml.load(Loader=OrderedDictYAMLLoader, *args, **kwargs)
def dump(*args, **kwargs):
if 'default_flow_style' not in kwargs:
kwargs['default_flow_style'] = False
return yaml.dump(Dumper=OrderedDictYAMLDumper, *args, **kwargs)
else: # pragma: no cover
def load(*args, **kwargs):
raise morphlib.Error('YAML not available')
def dump(*args, **kwargs):
raise morphlib.Error('YAML not available')
|