使用 ruamel.yaml 修改 YAML 会添加额外的新行
Posted
技术标签:
【中文标题】使用 ruamel.yaml 修改 YAML 会添加额外的新行【英文标题】:Modifying YAML using ruamel.yaml adds extra new lines 【发布时间】:2017-06-29 13:40:43 【问题描述】:我需要为 YAML 文件中的现有键添加一个额外的值。以下是我正在使用的代码。
with open(yaml_in_path, 'r') as f:
doc, ind, bsi = load_yaml_guess_indent(f, preserve_quotes=True)
doc['phase1'] += ['c']
with open(yaml_out_path, 'w') as f:
ruamel.yaml.round_trip_dump(doc, f,
indent=2, block_seq_indent=bsi)
这是输入和输出。
输入
phase1:
- a
# a comment.
- b
phase2:
- d
输出
phase1:
- a
# a comment.
- b
- c
phase2:
- d
如何摆脱b
和c
之间的新行? (当phase1
是文件中的唯一键或phase1
和phase2
之间没有空行时,不会出现此问题。)
【问题讨论】:
【参考方案1】:这里的问题是空行被认为是一种注释,ruamel.yaml
中的 cmets 通过将它们与序列中的元素或映射中的键相关联来保留。该值存储在名为 ca
的复杂属性中,在列表中,如对象 doc['phase1']
,与第二个元素相关联。
您当然可以争辩说它应该与***映射/字典相关联,或者与键 phase1
相关联(作为一些最终的空行评论)或与 phase2
作为一些介绍性的空行评论相关联.
上述三个中的任何一个都是有效的,并且库中目前无法控制空行(或注释)所在的策略。
如果您输入“真实”评论(以#
开头的评论),它将与phase1
关联作为结束评论,因为策略不同。
这显然需要大修,因为ruamel.yaml
的最初目标是:
- 从 YAML 加载一些配置
- 改变一些值
- 将配置保存到 YAML
在这种情况下,不会出现此类附加/插入问题。
因此,只有在扩展库并控制附加(尾随)cmets 和/或空行的位置之前,没有真正的解决方案。
在实施此类控制之前,您可以做的最好的事情可能是:
import sys
import ruamel.yaml
yaml_str = """\
phase1:
- a
# a comment.
- b
phase2:
- d
"""
def append_move_comment(l, e):
i = len(l) - 1
l.append(e)
x = l.ca.items[i][0] # the end comment
if x is None:
return
l.ca.items[i][0] = None
l.ca.items[i+1] = [x, None, None, None]
data = ruamel.yaml.round_trip_load(yaml_str)
append_move_comment(data['phase1'], 'c')
ruamel.yaml.round_trip_dump(data, sys.stdout, indent=4, block_seq_indent=2)
我将 indent
的值更改为 4,这是您输入的值(并得到,因为您将它指定为对于 block_seq_indent 而言很小)。
【讨论】:
谢谢。你能解释一下分配 [x, None, None, None] 而不是 [x] 的原因吗?以及在哪里可以查看 ruamel.yaml 的源代码来理解这个数据结构? 我不确定我是否在所有情况下都正确检查了该列表的长度,您也许可以少花钱,但我不会尝试。这不是故意记录的,因为它可以在未来的版本中更改。ca
属性是ruamel.yaml.comments.Comment()
的一个实例,x
是ruamel.yaml.tokens.CommentToken()
。提示:如果你没有人可以问,请使用print(type(l.ca),'\n', type(x))
;-)。
嘿@Anthon,我刚刚偶然发现了同样的问题。自从您发布此答案以来,是否有任何更新?现在有可能以更优雅的方式避免这种情况吗?谢谢!
@jakubka 不,没有(对不起,一直在忙着搬家和装修,最后是接近但不近,所以不要屏住呼吸)。以上是关于使用 ruamel.yaml 修改 YAML 会添加额外的新行的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 中使用 ruamel.yaml 从 YAML 文件中获取注释?