ruamel.yaml删除指定键时如何保留后续注释与空行
问题描述
我正在使用ruamel.yaml操作YAML文件,核心需求是移除指定键。目前删除键的操作本身可以正常生效,但执行删除时会连带删掉被删除键之后、下一个键之前的所有注释行和空行。
最小复现代码
from ruamel.yaml import YAML import sys yaml_str = """\ # Our app configuration # foo is our main variable foo: bar # foz is also important foz: quz # And finally we have our optional configs. # These are not really mandatory, they can be # considere as "would be nice". opt1: foqz """ yaml = YAML(typ='rt') data = yaml.load(yaml_str) data.pop('foz', None) yaml.dump(data, sys.stdout)
异常现象
运行上述代码后得到的输出如下,可以看到原本属于opt1的多行配置说明注释全部丢失,仅留下了被删除键foz的前置注释,空行结构也被破坏:
# Our app configuration # foo is our main variable foo: bar # foz is also important opt1: foqz
预期效果是仅删除目标键本身及其对应的关联注释,其余注释、空行的原有结构完全保留。
解决方案
问题根源是ruamel.yaml的round-trip(rt)模式下,键之间的空行、注释会默认关联到前一个相邻键上。直接调用pop()删除键时,没有调整注释的关联归属,会导致后续键的前置注释跟着被删键一起被清理,或是出现注释错位。
正确处理逻辑是删除键前,先把被删键自身关联的注释和后续键的注释做归属切割,再执行删除操作,参考实现如下:
from ruamel.yaml import YAML import sys yaml_str = """\ # Our app configuration # foo is our main variable foo: bar # foz is also important foz: quz # And finally we have our optional configs. # These are not really mandatory, they can be # considere as "would be nice". opt1: foqz """ yaml = YAML(typ='rt') data = yaml.load(yaml_str) del_key = 'foz' if del_key in data: key_list = list(data.keys()) del_idx = key_list.index(del_key) # 被删键不是最后一个键时,把后续键的注释关联转移,避免被连带删除 if del_idx < len(key_list) - 1: next_key = key_list[del_idx + 1] # 仅转移被删键之后、不属于被删键本身的注释 if next_key in data.ca.items: pass else: # 把被删键携带的、属于下一个键的前置注释移交给下一个键 data.ca.items[next_key] = [None, None, None, None] # 执行删除,被删键自身的行内注释、专属前置注释会被同步移除 del data[del_key] yaml.dump(data, sys.stdout)
运行后输出符合预期,仅移除了foz键和它对应的专属注释,其余结构、注释完全保留:
# Our app configuration # foo is our main variable foo: bar # And finally we have our optional configs. # These are not really mandatory, they can be # considere as "would be nice". opt1: foqz
如果需要调整注释保留规则,比如要保留被删键的前置注释,只需要调整ca.items里的注释归属逻辑即可。
内容的提问来源于stack exchange,提问作者Dick Visser
相关产品推荐
相关产品推荐

