Issue #13 new

Loading and then dumping an !!omap is broken

Anonymous created an issue

When you load and then dump yaml containing an !!omap, the !!omap is no dumped back correctly, using a the standard Dumper you will get a sequence of !!python/tuple and when using the safe Dumper a sequence of sequences

Example:

!!omap
- a: 123
- b: 456

You get upon loading:

[('a', 123), ('b', 456)]

And upon dumping:

[!!python/tuple [a, 123], !!python/tuple [b, 456]]

Or safe dumping:

[[a, 123], [b, 456]]

Comments (1)

  1. Erik Bray

    As is that behavior makes sense. But I've argued in the past that an !!omap should be loaded as an OrderedDict and that dumping an OrderedDict should produce an !!omap. Problem is that OrderedDict was not in the stdlib when this was first written, but now it is. And it's easy to include a backport of it to support older Python versions too. FWIW you can add better support for !!omap using OrderedDict like so:

    >>> import yaml
    >>> from collections import OrderedDict
    >>> def ordereddict_constructor(loader, node):
    ...     try:
    ...         omap = loader.construct_yaml_omap(node)
    ...         return OrderedDict(*omap)
    ...     except yaml.constructor.ConstructorError:
    ...         return loader.construct_yaml_seq(node)
    ... 
    >>> def represent_ordereddict(dumper, data):
    ...     # TODO: Again, adjust for preferred flow style, and other stylistic details
    ...     # NOTE: For block style this uses the compact omap notation, but for flow style
    ...     # it does not.
    ...     values = []
    ...     node = yaml.SequenceNode(u'tag:yaml.org,2002:seq', values, flow_style=True)
    ...     if dumper.alias_key is not None:
    ...         dumper.represented_objects[dumper.alias_key] = node
    ...     for key, value in data.items():
    ...         key_item = dumper.represent_data(key)
    ...         value_item = dumper.represent_data(value)
    ...         node_item = yaml.MappingNode(u'tag:yaml.org,2002:map', [(key_item, value_item)],
    ...                                      flow_style=False)
    ...         values.append(node_item)
    ...     return node
    ...
    >>> yaml.add_constructor(u'tag:yaml.org,2002:seq', ordereddict_constructor)
    >>> yaml.add_representer(OrderedDict, represent_ordereddict)
    >>> omap = """
    ... - c: 1
    ... - b: 2
    ... - d: 3
    ... - a: 4
    ... """
    >>> print yaml.dump(yaml.load(omap))
    - c: 1
    - b: 2
    - d: 3
    - a: 4
    
  2. Log in to comment