使用 ruamel.yaml 修改 YAML 添加额外的新行

Modifying YAML using ruamel.yaml adds extra new lines

我需要向 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 之间没有空行时,不会出现此问题。)

这里的问题是空行被认为是一种注释,ruamel.yaml 中的注释通过将它们与序列中的元素或映射中的键相关联来保留。该值存储在名为 ca 的复杂属性中,在列表中,如对象 doc['phase1'],与第二个元素关联。

你当然可以争辩说它应该在顶层 mapping/dict 与键 phase1 相关联(作为一些最终的 empty-line-comment)或与 phase2 相关联作为一些介绍 empty-line-comment。 以上三个中的任何一个都是有效的,并且库中目前没有对策略的控制,其中空行(或注释)。

如果您输入 "real" 评论(以 # 开头),它 phase1 相关联作为结束评论,对于那些策略是不同的。

这显然需要大修,因为 ruamel.yaml 的最初目标是: - 从 YAML 加载一些配置 - 改变一些价值 - 将配置保存到 YAML 在这种情况下,此类 append/insert 问题不会出现。

因此,在对库进行扩展并控制附加(尾随)注释的位置之前,没有真正的解决方案and/or 空行。

在实施此类控制之前,您最好做的可能是:

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 指定为较小值)。