Disable map merges and simply treat them as strings

34 Views Asked by At

I have a yaml file that has merge statement as below with undefined aliases. I am aware that such a yaml is invalid. However, I am dealing with a special case where, I need to be able to load the yaml successfully keeping the merge statement. Is it possible to achieve this?

yaml_str = """\
hello1 : world
foo:
    <<: *core_foo
"""

when I load using ruamel.yaml.Yaml().load(yaml_str) I want yaml to treat << and * just as any other strings and not error on undefined aliases

1

There are 1 best solutions below

2
Anthon On

Without changing the innards of the parser, the only way to load << without being interpreted as a merge key is by using the base loader, that treats every scalar as a string. But that still cannot deal with aliasses with appropriate anchors, so for that I suggest you replace the actual asterisks with a different character:

import sys
import ruamel.yaml

yaml_str = """\
hello1 : world
foo:
    <<: *core_foo
"""

yaml = ruamel.yaml.YAML(typ='base')
data = yaml.load(yaml_str.replace(': *', ': ★'))
print(data)

which gives:

{'hello1': 'world', 'foo': {'<<': '★core_foo'}}

After loading you could recursively walk over the data structure and revert the back to a *.

If you need to dump this back, make sure to create a new YAML instance that doesn't have typ="base". That way you can e.g. replace the merge key, and revert to a non-YAML, alias-only document

data['foo']['abc'] = data['foo'].pop('<<')


yaml2 = ruamel.yaml.YAML()
def revert(s):
    return s.replace('★', '*')

yaml2.dump(data, sys.stdout, transform=revert)

which gives:

hello1: world
foo:
  abc: *core_foo