Home > Net >  Best way to store multiple values of a key in a file, while also being able to append keys and value
Best way to store multiple values of a key in a file, while also being able to append keys and value

Time:05-12

I am currently programming a Soundboard. For that I would need to store the usergiven name of the sound, its path and a hotkey assigned to it. I also want the user to be able to add sounds whenever they like.

In a YAML document it would look something like this:

sounds:
    sound1:
        path: ...
        name: ...
        hotkey: ...
    sound2:
        path: ...
        name: ...
        hotkey: ...

Sadly I haven't found an easy way to append keys (sound3, sound4...) to a yaml like this. Is there an easy way to accomplish my goal?

CodePudding user response:

You load it into memory, edit it as a python data structure, then dump it back out to the yaml file.

import yaml

with open("t.yaml") as f:
    data = yaml.load(f, Loader=yaml.SafeLoader)

data['sounds']['sound3'] = {'path': '...', 'name': '...', 'hotkey': '...'}

with open("t.yaml", "w") as f:
    yaml.dump(data, f)

CodePudding user response:

Although it is theoretically possible to append to a YAML document, it is not practical in all but the most controlled environments (length of entries that might cause wrapping, data structure, indentation, etc.). If you are not adding elements to a root-level sequence or keys to root-level mapping, I would not even start to try it.

What you should do is load the document into a Python data structure and dump the whole structure back. If you care about preserving the format, quoting and commenting of the document you can do this using:

import sys
from pathlib import Path
import ruamel.yaml

file_path = Path('sound.yaml')

new_sound = dict(path='/path/to/sound', name='sndname', hotkey='Alt S')

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
data = yaml.load(file_path)
sounds = data['sounds']
idx = 0
while True:
    idx  = 1
    if (key := f'sound{idx}') not in sounds:
        sounds[key] = new_sound
        break
yaml.dump(data, file_path)

print(file_path.read_text())

which gives:

sounds:
    sound1:
        path: ..
        name: ..
        hotkey: ..
    sound2:
        path: ..
        name: ..
        hotkey: ..
    sound3:
        path: /path/to/sound
        name: sndname
        hotkey: Alt S

The above searches for the first free key of the form soundNNN and inserts the new data in the structure. If the input would have had quotes around scalar values (i.e. those loaded as Python strings), they would be preserved, as would EOL comments in the YAML document.

  • Related