使用 deepmerge python 模块并使用 ruamel.yaml 合并 2 个 yaml 时保留注释的问题
Issue in preserving comments when merging 2 yamls using deepmerge python module and using ruamel.yaml
代码:
from deepmerge import always_merger
import ruamel.yaml
fileA = "source.yaml"
fileB = "dest.yaml"
yaml = ruamel.yaml.YAML()
with open(fileA,'r+') as f:
fileAdictionary= yaml.load(f)
with open(fileB,'r+') as f:
fileBdictionary = yaml.load(f)
result = always_merger.merge(fileAdictionary, fileBdictionary)
with open('output.yaml','w+') as f:
yaml.dump(result,f)
source.yaml
element:
connection:
test: true
dest.yaml
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: "abc"
# comment for string parameter
test_int_param: 10
# comment for the integer parameter
test_bool_param: true
# comment for the boolean parameter
实际输出
output.yaml
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: abc
test_int_param: 10
test_bool_param: true
问题描述
如您在 output.yaml 中所见,元素 test_str_param
、test_int_param
和 test_bool_param
的注释未保留或继承自 dest.yaml
预期
需要做什么才能在最终 output.yaml
中保留与所有参数有关的所有注释
预期输出
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: "abc"
# comment for string parameter
test_int_param: 10
# comment for the integer parameter
test_bool_param: true
# comment for the boolean parameter
您从输入中加载的是 CommentedMap
个实例,这些是子 类
dict
个。 deepmerge
将它们作为指令处理,但因为它没有做任何特别的事情
对于注释,如果键合并到一个已经存在的文件中,您将丢失它们
CommentedMap
(如 fileAdictionary['element']
),但不是当一个值被合并到
是一个 CommentedMap
并且在 fileAdictionary
中还不存在(即没有
fileAdictionary['element']['networkPolicy']
)
deepmerge
允许你添加自己的策略,但我不确定是什么
best/recommended 添加新类型的过程:
import sys
from pathlib import Path
# from deepmerge import always_merger
import deepmerge
import ruamel.yaml
RYCM = ruamel.yaml.comments.CommentedMap
class CommentedMapStrategies(deepmerge.strategy.core.StrategyList):
NAME = 'CommentedMap'
@staticmethod
def strategy_merge(config, path, base, nxt):
for k, v in nxt.items():
if k not in base:
base[k] = v
else:
base[k] = config.value_strategy(path + [k], base[k], v)
try:
for k, v in nxt.ca.items.items():
base.ca.items[k] = v
except AttributeError:
pass
return base
@staticmethod
def strategy_override(config, path, base, nxt):
"""
move all keys in nxt into base, overriding
conflicts.
"""
return nxt
# insert as it needs to be before 'dict'
deepmerge.DEFAULT_TYPE_SPECIFIC_MERGE_STRATEGIES.insert(0, (RYCM, 'merge'))
Merger = deepmerge.merger.Merger
Merger.PROVIDED_TYPE_STRATEGIES[RYCM] = CommentedMapStrategies
always_merger = Merger(deepmerge.DEFAULT_TYPE_SPECIFIC_MERGE_STRATEGIES, ['override'], ['override'])
fileA = Path('source.yaml')
fileB = Path('dest.yaml')
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)
result = always_merger.merge(yaml.load(fileA), yaml.load(fileB))
yaml.dump(result, sys.stdout)
给出:
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: abc
# comment for string parameter
test_int_param: 10
# comment for the integer parameter
test_bool_param: true
# comment for the boolean parameter
根据您在 YAML 文档中的注释位置,您可能需要 amend/complete
在 strategy_merge
.
中复制评论
请注意,以上内容依赖于 CommentedMap
可能会发生变化的内部结构,
所以在升级之前固定 ruamel.yaml
版本并进行测试。
代码:
from deepmerge import always_merger
import ruamel.yaml
fileA = "source.yaml"
fileB = "dest.yaml"
yaml = ruamel.yaml.YAML()
with open(fileA,'r+') as f:
fileAdictionary= yaml.load(f)
with open(fileB,'r+') as f:
fileBdictionary = yaml.load(f)
result = always_merger.merge(fileAdictionary, fileBdictionary)
with open('output.yaml','w+') as f:
yaml.dump(result,f)
source.yaml
element:
connection:
test: true
dest.yaml
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: "abc"
# comment for string parameter
test_int_param: 10
# comment for the integer parameter
test_bool_param: true
# comment for the boolean parameter
实际输出
output.yaml
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: abc
test_int_param: 10
test_bool_param: true
问题描述
如您在 output.yaml 中所见,元素 test_str_param
、test_int_param
和 test_bool_param
的注释未保留或继承自 dest.yaml
预期
需要做什么才能在最终 output.yaml
预期输出
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: "abc"
# comment for string parameter
test_int_param: 10
# comment for the integer parameter
test_bool_param: true
# comment for the boolean parameter
您从输入中加载的是 CommentedMap
个实例,这些是子 类
dict
个。 deepmerge
将它们作为指令处理,但因为它没有做任何特别的事情
对于注释,如果键合并到一个已经存在的文件中,您将丢失它们
CommentedMap
(如 fileAdictionary['element']
),但不是当一个值被合并到
是一个 CommentedMap
并且在 fileAdictionary
中还不存在(即没有
fileAdictionary['element']['networkPolicy']
)
deepmerge
允许你添加自己的策略,但我不确定是什么
best/recommended 添加新类型的过程:
import sys
from pathlib import Path
# from deepmerge import always_merger
import deepmerge
import ruamel.yaml
RYCM = ruamel.yaml.comments.CommentedMap
class CommentedMapStrategies(deepmerge.strategy.core.StrategyList):
NAME = 'CommentedMap'
@staticmethod
def strategy_merge(config, path, base, nxt):
for k, v in nxt.items():
if k not in base:
base[k] = v
else:
base[k] = config.value_strategy(path + [k], base[k], v)
try:
for k, v in nxt.ca.items.items():
base.ca.items[k] = v
except AttributeError:
pass
return base
@staticmethod
def strategy_override(config, path, base, nxt):
"""
move all keys in nxt into base, overriding
conflicts.
"""
return nxt
# insert as it needs to be before 'dict'
deepmerge.DEFAULT_TYPE_SPECIFIC_MERGE_STRATEGIES.insert(0, (RYCM, 'merge'))
Merger = deepmerge.merger.Merger
Merger.PROVIDED_TYPE_STRATEGIES[RYCM] = CommentedMapStrategies
always_merger = Merger(deepmerge.DEFAULT_TYPE_SPECIFIC_MERGE_STRATEGIES, ['override'], ['override'])
fileA = Path('source.yaml')
fileB = Path('dest.yaml')
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)
result = always_merger.merge(yaml.load(fileA), yaml.load(fileB))
yaml.dump(result, sys.stdout)
给出:
element:
connection:
test: true
networkPolicy:
enabled: true
# network policy has been enabled
test_str_param: abc
# comment for string parameter
test_int_param: 10
# comment for the integer parameter
test_bool_param: true
# comment for the boolean parameter
根据您在 YAML 文档中的注释位置,您可能需要 amend/complete
在 strategy_merge
.
请注意,以上内容依赖于 CommentedMap
可能会发生变化的内部结构,
所以在升级之前固定 ruamel.yaml
版本并进行测试。