Search code examples
ruamel.yaml

How to add new references to a yaml-loaded dict?


I'm loading a yaml dictionary and would like to use some of the existing anchors to extend the dictionary before writing it out again. Is this possible?

Example, let's say I have a yaml file:

a: &a 1
b: &b 2

With ruamel, how would I add a new value c that refereces a. In other words, how do I write:

a: &a 1
b: &b 2
c: *a

Solution

  • The anchored scalar 1 is loaded in ruamel.yaml as a ScalarInt and not as an integer, as on the integer there would be no place to attach the actual anchor name, and more importantly because dumping the same integer will not result in an anchored scalar and aliases. However when the same ScalarInt instance is dumped you'll get an anchor for the first and aliases for all other occurences.

    (ScalarInt will behave like normal integers for all common purposes, if you just need to use the loaded data.)

    To get the output you want, you need to have the value that is associated with key c to be the same as the value for a. You can just do that simply by assigning:

    import sys
    import ruamel.yaml
    
    yaml_str = """\
    a: &a 1
    b: &b 2
    """
    
    yaml = ruamel.yaml.YAML()
    data = yaml.load(yaml_str)
    data['c'] = data['a']
    yaml.dump(data, sys.stdout)
    

    which gives:

    a: &a 1
    b: &b 2
    c: *a
    

    If you want to start from Python code instead of loading some YAML with anchors, you'll need to create the ScalarInts yourself:

    import sys
    import ruamel.yaml
    
    yaml = ruamel.yaml.YAML()
    a_val = ruamel.yaml.scalarint.ScalarInt(1, anchor='a')
    data = dict(a=a_val, b=ruamel.yaml.scalarint.ScalarInt(2, anchor='b'), c=a_val)
    yaml.dump(data, sys.stdout)
    

    this also gives:

    a: &a 1
    b: &b 2
    c: *a