使用 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

如何摆脱bc 之间的新行? (当phase1 是文件中的唯一键或phase1phase2 之间没有空行时,不会出现此问题。)

【问题讨论】:

【参考方案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() 的一个实例,xruamel.yaml.tokens.CommentToken()。提示:如果你没有人可以问,请使用print(type(l.ca),'\n', type(x)) ;-)。 嘿@Anthon,我刚刚偶然发现了同样的问题。自从您发布此答案以来,是否有任何更新?现在有可能以更优雅的方式避免这种情况吗?谢谢! @jakubka 不,没有(对不起,一直在忙着搬家和装修,最后是接近但不近,所以不要屏住呼吸)。

以上是关于使用 ruamel.yaml 修改 YAML 会添加额外的新行的主要内容,如果未能解决你的问题,请参考以下文章

在 ruamel.yaml 中保留引号

防止长行被包裹在 ruamel.yaml

ruamel.yaml的使用

如何在 Python 中使用 ruamel.yaml 从 YAML 文件中获取注释?

Python之ruamel.yaml模块详解| ruamel.yaml与pyyaml的区别

Python之ruamel.yaml模块详解