简体   繁体   中英

How to add new key value to yaml without overwriting it in python?

I have small python script which responsible for updating my yaml file by adding new records:

data = yaml.load(file)
data['WIN']['Machine'] = dict(node_labels='+> tfs vs2022')
data['WIN']['Machine'] = dict(vs='vs2022')
yaml.dump(data, file)

Every time when I run above script I will get updated yaml file like below:

WIN:
  Machine:
    vs: vs2022

My desired output to have both my key: value pairs

WIN:
  Machine:
    node_labels: +> tfs vs2022
    vs: vs2022

I'm wondering why line data['WIN'][nodeName] = dict(node_labels='+> tfs vs2022') overwritten by next line? How can add several key: values for Machine section?

This is not a YAML related problem, but a conceptual problem in your non-yaml related Python code.

By assigning a dict as value to the key Machine , you set that value. By assigning another dict to the key, you overwrite that value completely, erasing the previous key-value pair.

If you simplify your code:

data = dict(Machine=None)
data['Machine'] = dict(node_labels='+> tfs vs2022')
print('data 1', data)
data['Machine'] = dict(vs='vs2022')
print('data 2', data)

As you can see after the second assignment, the key node_labels is no longer available.

data 1 {'Machine': {'node_labels': '+> tfs vs2022'}}
data 2 {'Machine': {'vs': 'vs2022'}}

There are several ways to solve this. You can either assign a value to a key in the first dict:

data = dict(Machine=None)
data['Machine'] = added_dict = dict(node_labels='+> tfs vs2022')
print('data 1', data)
added_dict['vs'] ='vs2022'
print('data 2', data)

Now you have both keys in the second output:

data 1 {'Machine': {'node_labels': '+> tfs vs2022'}}
data 2 {'Machine': {'node_labels': '+> tfs vs2022', 'vs': 'vs2022'}}

If you don't already know there is a dict where you can add a key to, you might to use .setdefault , either using key-value assigment, and/or by using .update (useful for updating multiple keys in one go):

data = dict()
data.setdefault('Machine', {})['node_labels'] = '+> tfs vs2022'
print('data 1', data)
data.setdefault('Machine', {}).update(dict(vs='vs2022'))
print('data 2', data)
data 1 {'Machine': {'node_labels': '+> tfs vs2022'}}
data 2 {'Machine': {'node_labels': '+> tfs vs2022', 'vs': 'vs2022'}}

Of course you can put node_labels and vs in one dict and assign, but that would overwrite any existing key-values loaded from YAML. So the use of .update is IMO better:

import sys
from pathlib import Path
import ruamel.yaml

file_in = Path('input.yaml')
# key in YAML mapping with null value
file_in.write_text("""\
WIN:
""")
    
yaml = ruamel.yaml.YAML()
data = yaml.load(file_in)
if data['WIN'] is None:
    data['WIN'] = {}
data['WIN'].setdefault('Machine', {}).update(dict(node_labels='+> tfs vs2022'))
data['WIN'].setdefault('Machine', {}).update(dict(vs='vs2022'))
yaml.dump(data, sys.stdout)

which gives your expected result:

WIN:
  Machine:
    node_labels: +> tfs vs2022
    vs: vs2022

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM