Search code examples
yamlpython-3.6ruamel.yamlordereddict

How to remove a nested entry from Python OrderedDict (ruamel)?


I'm using https://github.com/wwkimball/yamlpath and the excellent ruamel YAML parser to load and work with YAML files. I need to remove an entry from a YAML file but can't see how to obviously do that. Here's an example:

Source YAML snippet:

sports:
  football:
    - Dallas Cowboys
    - Miami Dolphins
    - San Francisco 49ers

I can get the YAML paths to these but how can I delete (say) the Miami entry? Using ruamel.yaml gives me a data structure like this:

ordereddict([('sports', ordereddict([('football', ['Dallas Cowboys', 'Miami Dolphins', 'San Francisco 49ers'])]))])

I can access an entry by saying data['sports']['football'][0] but how can I remove that element from the YAML file? I see there's a "pop" option but what needs to be supplied in this example for nested keys?

I've looked at the yamlpath CLI tools and there doesn't seem to be a delete option.


Solution

  • Your 'Dallas Cowboys', is displayed as a the first element of a list, but it is actually a CommentedSeq, which is a subclass of a list that can hold comments and other information.

    However, you can delete an element from that, just like you would from any list, using del::

    import sys
    import ruamel.yaml
    
    yaml_str = """\
    sports:
      football:
        - Dallas Cowboys
        - Miami Dolphins
        - San Francisco 49ers
    """
    
    yaml = ruamel.yaml.YAML()
    yaml.indent(sequence=4, offset=2)
    data = yaml.load(yaml_str)
    print('debug:', type(data['sports']['football']), 
                         isinstance(data['sports']['football'], list), '\n')
    
    
    del data['sports']['football'][0]
    yaml.dump(data, sys.stdout)
    

    which gives:

    debug: <class 'ruamel.yaml.comments.CommentedSeq'> True 
    
    sports:
      football:
        - Miami Dolphins
        - San Francisco 49ers
    

    If you only have a pop option you would need to pop element 0, so substituting the del line in the above with:

     data['sports']['football'].pop(0)
    

    gives the same result.

    I hope either of those can be done with yamlpath