我有两个yaml文件,A.yaml(基础)和B.yaml(覆盖),我想用B文件覆盖A文件别名键值。
A.yaml:
A1: &A1
AA:
AAA: true
AAB: true
AB:
ABA: [1, 1, 1]
ABB: true
A2:
<<: *A1
AB:
ABA: [1, 2, 1] # overwrite anchor value by alias.
和B.yaml如下:
A2:
AB:
ABA: [2, 2, 2] # overwrite alias value.
覆盖的输出 yaml 将是这样的:
A1:
AA:
AAA: true
AAB: true
AB:
ABA: [1, 1, 1]
ABB: true
A2:
AA:
AAA: true
AAB: true
AB:
ABA: [2, 2, 2] # modified alias key
ABB: true # keep the original keys
我做过这样的东西,但是没法实现,有没有办法用PyYAML来满足要求?
import yaml
def _overrideCfg(data, over_data):
"""Override key values in data using over_data"""
if isinstance(data, dict) and isinstance(over_data, dict):
for key, value in over_data.items():
if key in data:
if isinstance(data[key], dict) and isinstance(value, dict):
_overrideCfg(data[key], value)
else:
# Override the value in the data dictionary
data[key] = value
else:
# Add the new key-value pair to the data dictionary
data[key] = value
# Serialize the updated data dictionary to YAML
output = yaml.dump(data, default_flow_style=False)
return output
else:
raise TypeError("Both data and over_data must be dictionaries")
# Load the YAML files
with open('A.yaml') as f:
data = yaml.safe_load(f)
with open('B.yaml') as f:
over_data = yaml.safe_load(f)
# Override the values in data using over_data
data = _overrideCfg(data, over_data)
# Print the updated YAML
with open('output.yaml', 'w') as f:
f.write(data)
加载后
A.yaml
你没有根级键ABB
下的键A2
,这就是PyYAML中合并的工作方式,你也
没有对原始锚定映射的引用。
所以加载后以某种方式深度合并
B.yaml
,永远不会让你找回那把钥匙。
相反,您可以使用另一个或额外的锚点/别名:
import sys
from pathlib import Path
import ruamel.yaml
path_a = Path('A.yaml')
path_b = Path('B.yaml')
path_a.write_text("""\
A1: &A1
AA:
AAA: true
AAB: true
AB: &another
ABA: [1, 1, 1]
ABB: true
A2:
<<: *A1
AB:
<<: *another
ABA: [1, 2, 1] # overwrite anchor value by alias.
""")
def overwrite(data, update):
for k, v in update.items():
if isinstance(v, dict):
overwrite(data[k], v)
else:
data[k] = v
yaml = ruamel.yaml.YAML()
data = yaml.load(path_a)
assert data['A2']['AA']['AAA']
assert data['A2']['AB']['ABB']
assert data['A2']['AB']['ABA'] == [1, 2, 1]
update = yaml.load(path_b)
overwrite(data, update)
assert data['A2']['AB']['ABB']
assert data['A2']['AB']['ABA'] == [2, 2, 2]
yaml.dump(data, sys.stdout)
给出:
A1: &A1
AA:
AAA: true
AAB: true
AB: &another
ABA: [1, 1, 1]
ABB: true
A2:
<<: *A1
AB:
<<: *another
ABA: [2, 2, 2] # overwrite anchor value by alias.
在上面
B.yaml
是你指定的。
如果您无法更改
A.yaml
,可以从原始A.yaml
开始并更新
加载文档就像加载一样
来自我一直在使用的A.yaml
。 PyYAML 不能这样做(因为它在加载期间解析合并键),并且
除此之外,它仅支持 YAML 1.1 规范的一个子集,该规范已于 2009 年(十四年前)过时。
IMO 它不应该用于新项目。