Reputation: 76802
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.Upvotes: 2
Views: 1060
Reputation: 76802
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.
Upvotes: 4