I'm using ruamel.yaml
to add an entry to a dictionary:
import ruamel.yaml
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(mapping=2, sequence=4, offset=2)
raw = """---
# Some config file..
# This is the main clients config
clients:
foobar1:
name: foo Bar 1
auth: false
count: 1290
barboz:
name: BarraBoz
auth: true
count: 19
uids_default: &uids_default
- attribute_email: mail
datafile: vars1
uids:
- <<: *uids_default
skip: true
- <<: *uids_default
issuer: http://foo.bar
"""
vanhelst = {"adfs": 124423423, "123": "adsfadsfasdf", "name": "Dirk Van helst"}
data = yaml.load(raw)
data["clients"].insert(len(data["clients"]), "vanhelst", vanhelst)
# Write to file
with open("/tmp/out.yml", "w") as f:
yaml.dump(data, f)
That works, the entry is added correctly, the comment is preserved. But it also changes some anchors that are in the file, to add aliases (?) like id001
:
# Some config file..
# This is the main clients config
clients:
foobar1:
name: foo Bar 1
auth: false
count: 1290
barboz:
name: BarraBoz
auth: true
count: 19
vanhelst:
adfs: 124423423
'123': adsfadsfasdf
name: Dirk Van helst
uids_default:
- &id001
attribute_email: mail
datafile: vars1
uids:
- <<: *id001
skip: true
- <<: *id001
issuer: http://foo.bar
Is there a way to not add those, and not touch the anchors at all?
You have only one anchor and two aliases. The anchor is on a sequence which contains a single mapping. You then use that data structure (i.e. the sequence) as a value for the <<
merge key. I have not seen anybody do that before. That sequence is flattened by the merge preserving code (as it contains only one mapping), that is why the anchor shifts from the sequence to the mapping it is containing.
So you can consider it is a bug in ruamel.yaml
, that its merge key handling cannot cope with aliases of anchored sequences. If you would have two elements in the sequence the merge key entry would look like:
- <<: [*id0001, *id0002]
I would remove the sequence from the value of uids_default
as long as you are not using the optional sequence. If you do things work:
import sys
import ruamel.yaml
yaml_str = """\
# Some config file..
# This is the main clients config
clients:
foobar1:
name: foo Bar 1
auth: false
count: 1290
barboz:
name: BarraBoz
auth: true
count: 19
uids_default: &uids_default
attribute_email: mail
datafile: vars1
uids:
- <<: *uids_default
skip: true
- <<: *uids_default
issuer: http://foo.bar
"""
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(mapping=2, sequence=4, offset=2)
vanhelst = {"adfs": 124423423, "123": "adsfadsfasdf", "name": "Dirk Van helst"}
data = yaml.load(yaml_str)
data["clients"].insert(len(data["clients"]), "vanhelst", vanhelst)
yaml.dump(data, sys.stdout)
which gives:
# Some config file..
# This is the main clients config
clients:
foobar1:
name: foo Bar 1
auth: false
count: 1290
barboz:
name: BarraBoz
auth: true
count: 19
vanhelst:
adfs: 124423423
'123': adsfadsfasdf
name: Dirk Van helst
uids_default: &uids_default
attribute_email: mail
datafile: vars1
uids:
- <<: *uids_default
skip: true
- <<: *uids_default
issuer: http://foo.bar
If you really need a merge of multiple mappings, anchor them each with different anchors and put the sequence of the corresponding aliases after the merge key.
You are still using .yml
as an extension. Please read the FAQ on yaml.org, and follow its recommendation.