Search code examples
pythonfileyamlpyyamlruamel.yaml

How do I update this yaml file with python and ruamel?


I have a test.yaml file with content:

school_ids:
  school1: "001"

  #important school2
  school2: "002"


targets:
  neighborhood1:
    schools:
      - school1-paloalto
    teachers:
      - 33
  neighborhood2:
    schools:
      - school2-paloalto
    teachers:
      - 35

I want to use ruamel to update the file to look like this:

school_ids:
  school1: "001"

  #important school2
  school2: "002"

  school3: "003"


targets:
  neighborhood1:
    schools:
      - school1-paloalto
    teachers:
      - 33
  neighborhood2:
    schools:
      - school2-paloalto
    teachers:
      - 35
  neighborhood3:
    schools:
      - school3-paloalto
    teachers:
      - 31

How do I use ruamel to update the file to get the desired output by preserving the comments?

Here's what I have so far:

import sys
from ruamel.yaml import YAML

inp = open('/targets.yaml', 'r').read()

yaml = YAML()

code = yaml.load(inp)
account_ids = code['school_ids']
account_ids['new_school'] = "003"
#yaml.dump(account_ids, sys.stdout)


targets = code['targets']
new_target = dict(neighborhood3=dict(schools=["school3-paloalto"], teachers=["31"]))
yaml = YAML()
yaml.indent(mapping=2, sequence=3, offset=2)
yaml.dump(new_target, sys.stdout)

Solution

  • You are just dumping new_target which you create from scratch not using the code or even targets. Instead you should either use that code that you loaded and extend the values associated with its root level keys and then dump code:

    import sys
    from pathlib import Path
    from ruamel.yaml import YAML
    
    inp = Path('test.yaml')
    
    yaml = YAML()
    
    code = yaml.load(inp)
    school_ids = code['school_ids']
    school_ids['school3'] = "003"
    
    
    targets = code['targets']
    targets['neighborhood3'] = dict(schools=["school3-paloalto"], teachers=["31"])
    yaml = YAML()
    yaml.indent(mapping=2, sequence=4, offset=2)
    yaml.dump(code, sys.stdout)
    

    which gives:

    school_ids:
      school1: '001'
    
      #important school2
      school2: '002'
    
    
      school3: '003'
    targets:
      neighborhood1:
        schools:
          - school1-paloalto
        teachers:
          - 33
      neighborhood2:
        schools:
          - school2-paloalto
        teachers:
          - 35
      neighborhood3:
        schools:
          - school3-paloalto
        teachers:
          - '31'
    

    Please note that your sequence indent needs to be at least 2 greater than your offset (2 positions to have room for - + SPACE)

    The output has the emtpy lines between after the key school2, as that is what these are associated with during parsing. This can be moved to the new key, but it is not trivial. If you need to do that (it is not important for the semantics of the YAML document), then have a look at my answer here