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 OrderedDict
s without getting the !!omap
tags and without
key-value as a single elements in a list?
CommentedMap
. OrderedDict
in
ruamel.yaml's CommentedMap
, but that is to slow.You can lookup how the CommentedMap
is registered with the RoundTripRepresenter
and use the same code for your OrderedDict
s. 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.