2

I have a YAML document in a file that I need to update with some structured information, that I get from a library. The order in which keys from this information are dumped is important.

The YAML file (input.yaml) looks like:

%YAML 1.1
---
- element 1  # this is the first element
- element 2

(please don't ask why the next program in the chain only support YAML 1.1, even though 1.2 has been out for over nine years)

My program:

import sys
from collections import OrderedDict
from pathlib import Path
import ruamel.yaml

path = Path('input.yaml')

yaml = ruamel.yaml.YAML()  # defaults to round-trip
yaml.version = (1, 1)
yaml.explicit_start = True

data = yaml.load(path)

data.append(
    OrderedDict([
        ('hosts', 'all'), 
        ('vars', {'some_var': True}),
        ('tasks', [
            OrderedDict([('name', 'print some_var'), ('debug', {'var': 'some_var'})])
        ]),
    ]))


yaml.dump(data, sys.stdout)

with output:

%YAML 1.1
---
- element 1  # this is the first element
- element 2
- !!omap
  - hosts: all
  - vars:
      some_var: true
  - tasks:
    - !!omap
      - name: print some_var
      - debug:
          var: some_var

How can I output the OrderedDicts without getting the !!omap tags and without key-value as a single elements in a list?

  • I am using ruamel.yaml to preserve existing comments.
  • I get this structure from a library, and I cannot specify that it should use ruamel.yaml's CommentedMap.
  • I know how to recursively walk over the structure, before appending, and converting OrderedDict in ruamel.yaml's CommentedMap, but that is to slow.
Anthon
  • 51,019
  • 25
  • 150
  • 211
  • This was first posted inappropriately as a vague comment to an issue on the ruamel.yaml issue tracker. Then once more as an equally unclear and inappropriate "major proposal". – Anthon Aug 21 '18 at 10:37

1 Answers1

4

You can lookup how the CommentedMap is registered with the RoundTripRepresenter and use the same code for your OrderedDicts. Actually, you only need one extra line:

yaml.Representer.add_representer(OrderedDict, yaml.Representer.represent_dict)

with that your program gives you:

%YAML 1.1
---
- element 1  # this is the first element
- element 2
- hosts: all
  vars:
    some_var: true
  tasks:
  - name: print some_var
    debug:
      var: some_var

You can also use the way PyYAML attaches the representer to the aggregate Dumper structure:

ruamel.yaml.add_representer(OrderedDict, ruamel.yaml.RoundTripDumper.represent_dict, Dumper=ruamel.yaml.RoundTripDumper)

but that is more verbose.

Anthon
  • 51,019
  • 25
  • 150
  • 211