''' A YAML Loader and Dumper which provide ordered dictionaries in place of dictionaries (to keep the order of attributes as found in the original YAML object file). This module is modified from a submission on pyyaml.org: http://pyyaml.org/attachment/ticket/161/use_ordered_dict.py $Id$ ''' import yaml import collections class Loader(yaml.loader.Loader): """ YAML Loader producing OrderedDicts in place of dicts """ def __init__(self, stream): yaml.loader.Loader.__init__(self, stream) def construct_ordered_mapping(self, node, deep=False): """ Replacement mapping constructor producing an OrderedDict """ if not isinstance(node, yaml.MappingNode): raise yaml.constructor.ConstructorError(None, None, "expected a mapping node, but found %s" % node.id, node.start_mark) mapping = collections.OrderedDict() for key_node, value_node in node.value: key = self.construct_object(key_node, deep=deep) if not isinstance(key, collections.Hashable): raise yaml.constructor.ConstructorError("while constructing a mapping", node.start_mark, "found unhashable key", key_node.start_mark) value = self.construct_object(value_node, deep=deep) mapping[key] = value return mapping # yaml.constructor.BaseConstructor.construct_mapping = construct_ordered_mapping def construct_mapping(self, node, deep=False): return self.construct_ordered_mapping(node, deep=deep) def construct_yaml_map_with_ordered_dict(self, node): data = collections.OrderedDict() yield data value = self.construct_mapping(node) data.update(value) class Dumper(yaml.dumper.Dumper): """ YAML Dumper producing documents from OrderedDicts """ def __init__(self, stream, *args, **kwargs): yaml.dumper.Dumper.__init__(self, stream, *args, **kwargs) def represent_ordered_mapping(self, tag, mapping, flow_style=None): """ Replacement mapping representer for OrderedDicts """ value = [] node = yaml.MappingNode(tag, value, flow_style=flow_style) if self.alias_key is not None: self.represented_objects[self.alias_key] = node best_style = True if hasattr(mapping, 'items'): mapping = list(mapping.items()) for item_key, item_value in mapping: 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 if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style): best_style = False value.append((node_key, node_value)) if flow_style is None: if self.default_flow_style is not None: node.flow_style = self.default_flow_style else: node.flow_style = best_style return node # yaml.representer.BaseRepresenter.represent_mapping = represent_ordered_mapping def represent_mapping(self, tag, mapping, flow_style=None): return self.represent_ordered_mapping(tag, mapping, flow_style=flow_style) # Loader.add_constructor( # u'tag:yaml.org,2002:map', # Loader.construct_yaml_map_with_ordered_dict # ) # # Dumper.add_representer( # collections.OrderedDict, # yaml.representer.SafeRepresenter.represent_dict # )