Search code examples
pythonpython-2.7pyyamlruamel.yaml

Keep anchors & aliases on load/dump YAML using ruamel.yaml


How can I avoid ruamel.yaml from merging anchors when using yaml.load? I would like to keep file as is, just modify some keys such as production -> host & production -> port and dump to file

defaults: &defaults
  host: <%= ENV.fetch("VBOX_IP", "127.0.0.1") %>
  adapter: mysql2
  reconnect: true
  encoding: utf8
  username: root

production:
  default:
    <<: *defaults
    host: dbname.domain.com
    port: 3306

Solution

  • If you have that YAML example in file config.yaml then you can do:

    import sys
    import ruamel.yaml
    
    
    yaml = ruamel.yaml.YAML()
    
    with open('config.yaml') as ifp:
        data = yaml.load(ifp)
    data['defaults']['reconnect'] = False
    data['production']['default']['port'] += 1
    
    with open('config.yaml', 'w') as ofp:
        yaml.dump(data, ofp)
    

    to get an updated file:

    defaults: &defaults
      host: <%= ENV.fetch("VBOX_IP", "127.0.0.1") %>
      adapter: mysql2
      reconnect: false
      encoding: utf8
      username: root
    
    production:
      default:
        <<: *defaults
        host: dbname.domain.com
        port: 3307
    

    The default YAML() (equivalent to YAML(typ='rt')) will get you the round-trip loader/dumper that preserves both the anchor name and the merge key (<<).

    Please note that if you would do:

    data['production']['default']['reconnect'] = 'False'
    

    then the reconnect key would be added to the mapping that starts with the merge key.