Search code examples
pythonyamlpyyaml

Python iterate through YAML


How can one iterate through:

A:
  A1: 1000
  A2:
    A2A:
      A2A1: 100
      A2A2: 250
      A2A3: 250
    A2B:
      A2B1: 100
      A2B2: 300
   A3:
     A3A:
       A3A1:
         A3A1A: 200
         A3A1B: 100
         # There could be more values

I want to add the values of A3A1A and A3A1B and other values in the same place

I tried the following:

    with open("foobar.yml", 'r') as stream:
            foobar = yaml.load(stream)
    end_value = 0
        for one_value in foobar["A1"]["A3"]["A3A"] ["A3A1"][*]:
           end_value = end_value + one_value 

but this doesn't work


Solution

  • There are several problems here:

    • Your YAML is invalid. The key A3 does not align with A2 (or A2B). I assume you want it aligned with A2
    • the key in the root level mapping is A not A1, so you should start with foobar['A'] to traverse the data structure.
    • there is no such thing as [*] use .items() to get the key-value pairs, or .values() to only get the values of the nested mapping/dict
    • your for statement is incorrectly indented
    • you are using PyYAML's load() which is documented to be potentially unsafe, and there is no need to use it. Use safe_load(), or upgrade to ruamel.yaml which gives you YAML 1.2 and much more (disclaimer: I am the author of ruamel.yaml)

    E.g. you can do:

    import sys
    import ruamel.yaml
    
    
    yaml = ruamel.yaml.YAML(typ='safe')
    with open('foobar.yaml') as fp:
      data = yaml.load(fp)
    
    end_value = 0
    for one_value in  data['A']['A3']['A3A']['A3A1'].values():
       end_value += one_value
    
    print(end_value)
    

    which gives:

    300