Update YAML file programmatically

I have a Python dict that comes from reading a YAML file using regular

yaml.load(stream)

I want to update the YAML file programmatically by specifying the path to update, for example:

group1, option1, option11, value

and save the resulting dict again as a yaml file. I ran into a dicntionary update problem, given that the path is dynamic (suppose the user can enter the path through a simple CLI that I created using Cmd).

Any ideas?

thank!

UPDATE Let me clarify the question: the problem is updating the part of the dictionary where I do not know the structure in advance. I am working on a project where the entire configuration is stored in YAML files, and I want to add CLIs to avoid having to edit them manually. This is an example of a YAML file loaded into a dictionary (config-dict) using PyYaml:

config:
 a-function: enable
 b-function: disable
 firewall:
  NET:
   A:
    uplink: enable
    downlink: enable
   B:
    uplink: enable
    downlink: enable
  subscriber-filter:
   cancellation-timer: 180
 service:
  copy:
   DS: enable
  remark:
   header-remark:
    DSC: enable
    remark-table:
 port:
  linkup-debounce: 300
  p0:
   mode: amode
  p1:
   mode: bmode
  p2:
   mode: amode
  p3:
   mode: bmode

I created a CLI with Cmd and it works great even with autocomplete. The user can provide a string, for example:

config port p1 mode amode

So I need to edit:

config-dict ['config'] ['port'] ['p1'] ['mode'] and set it to "amode". Then use yaml.dump () to create the file again. Another possible line:

config a-function enable

So config-dict ['config'] ['a-function'] must be set to 'enable'.

. Python , : dict , . , Cmd. , .

, !

.

+4
4

patter: load - modify - dump:

, pyyaml:

$ pip install pyyaml

testyaml.py

import yaml
fname = "data.yaml"

dct = {"Jan": {"score": 3, "city": "Karvina"}, "David": {"score": 33, "city": "Brno"}}

with open(fname, "w") as f:
    yaml.dump(dct, f)

with open(fname) as f:
    newdct = yaml.load(f)

print newdct
newdct["Pipi"] = {"score": 1000000, "city": "Stockholm"}

with open(fname, "w") as f:
    yaml.dump(newdct, f)

data.yaml

$ cat data.yaml
David: {city: Brno, score: 33}
Jan: {city: Karvina, score: 3}
Pipi: {city: Stockholm, score: 1000000}
+16

python-benedict, python dict, - , yaml.

: pip install python-benedict

yaml:

from benedict import benedict

f = 'data.yaml'
d = benedict.from_yaml(f)
d['Pipi'] = {'score': 1000000, 'city': 'Stockholm'}

# benedict supports keypath (dot syntax by default),
# so it possible to update nested values easily:
d['Pipi.score'] = 2000000
print(d['Pipi']) # -> {'score': 2000000, 'city': 'Stockholm'}

d.to_yaml(filepath=f)

:https://github.com/fabiocaccamo/python-benedict

+1

, . yaml.load , (a) ppend . , , , .

newinfo = {"Pipi": {"score": 100000, "city": "Stockholm"}}
with open(fname, "a") as f:
     sep = "\n" # For distinct documents use "\n...\n" as separator

     # Pay attention to where you put the separator. 
     # if the file exists and is in traditional format place at 
     # beginning of string. else place at the end.

     infostring = "{}".format(newinfo)
     f.write(infostring + sep)

, . json.dump . , YAML, , python YAML.

OS os.linesep.

. , .

0

Try this method, I use to update YAML or JSON files. def update_dictionary_recursively(dictionary, key, value, key_separator="."): """Update givendictionary with the givenkey andvalue. "

if dictionary contains value as dict E.g. {key1:value1, key2:{key3, {key4:value4}}} and you have to
update key4 then 'key' should be given as 'key2.key3.key4'.

If dictionary contains value as list E.g. {key1:{key2:[{key3:valie3}, {key4:value4}]}} and you have to update
key4 then 'key' should be given as 'key1.key2[1].key4'.

:param dictionary: Dictionary that is to be updated.
:type dictionary: dict
:param key: Key with which the dictionary is to be updated.
:type key: str
:param value: The value which will be used to update the key in dictionary.
:type value: object
:param key_separator: Separator with which key is separated.
:type key_separator str
:return: Return updated dictionary.
:rtype: dict
"""
index = key.find(key_separator)
if index != -1:
    current_key = key[0:index]
    key = key[index + 1:]
    try:
        if '[' in current_key:
            key_index = current_key.split('[')
            current_key = key_index[0]
            list_index = int(key_index[1].strip(']'))
            dictionary[current_key][list_index] = update_dictionary_recursively(
                dictionary[current_key][list_index], key, value, key_separator)
        else:
            dictionary[current_key] = update_dictionary_recursively(dictionary[current_key],
                                                                                    key, value, key_separator)
    except (KeyError, IndexError):
        return dictionary
else:
    if '[' in key:
        key_index = key.split('[')
        list_index = int(key_index[1].strip(']'))
        if list_index > len(dictionary) - 1:
            return dictionary
        dictionary[list_index] = value
    else:
        if key not in dictionary:
            return dictionary
        dictionary[key] = value
return dictionary

"

0
source

Source: https://habr.com/ru/post/1542348/


All Articles