Deepcopy YAML和Python中的顶级列表注释

时间:2019-06-20 19:20:08

标签: python yaml pyyaml ruamel.yaml

我正在尝试使用ruamel.yaml将以下yaml文件转储到多个(不同的)文件中:

C:
  f:
  # comment
  - - l1
    - l2: '5'

如果我尝试执行deepcopy,则注释会导致深度复制版本的错误:

import copy

from ruamel.yaml import YAML

yaml = YAML()

conf = None
with open("input.yaml", 'r') as inf:
    conf = yaml.load(inf)
conf2 = copy.deepcopy(conf)

with open("out1.yaml", 'w') as outf:
    yaml.dump(conf, outf)

try:
    with open("out2.yaml", 'w') as outf:
        yaml.dump(conf2, outf)
    print("all good")
except AssertionError:
    raise SystemExit("Deep copy failed")

是否有一种方法可以将带有此类注释的已加载YAML转储到多个文件中?

1 个答案:

答案 0 :(得分:2)

主要是由于ruamel.yaml开发 不是从注释# comment所属的数据结构的规范开始(现在也没有)。更容易的事实 向已创建的节点添加评论(即 解析器遇到注释之前的YAML文档)而不是添加它 到下一个节点(在文档末尾可能不会显示) 上)。

在您的示例中,注释可以与键f关联,以 单元素序列的第一个元素,或到第一个元素 双重项目顺序的ruamel.yaml确实尝试进行一些重新排列, 导致过去的一次评论与 两个连续的节点,这就是merge_comments试图通过观察来解决 这些评论是否相等。

这是一个权宜之计,但效果很好 如果您将ruamel.yaml用于其预期的load-modify-save用途,则使用Deepcopy 不保留此引用,从而导致不平等,因此AssertionError

快速而肮脏的解决方案是使merge_comments成为无操作人员:

import copy
from ruamel.yaml import YAML

yaml = YAML()

conf = None
with open("input.yaml", 'r') as inf:
    conf = yaml.load(inf)
conf2 = copy.deepcopy(conf)

with open("out1.yaml", 'w') as outf:
    yaml.dump(conf, outf)

yaml.representer.merge_comments = lambda x, y: None

try:
    with open("out2.yaml", 'w') as outf:
        yaml.dump(conf2, outf)
    print("all good")
except AssertionError:
    raise SystemExit("Deep copy failed")

给出:

all good

带有out1.yaml的内容:

C:
  f:
  # comment
  - - l1
    - l2: '5'

out2.yaml中的

C:
  f:
  # comment
  - - l1
    - l2: '5'

此问题被“增强”为__deepcopy__ 列表和映射的表示形式,对 包含注释,流,格式,锚点等信息的属性 不遵循the documentation中的建议:

  

如果 deepcopy ()实现需要对文件进行深拷贝     组件,则应使用该组件调用deepcopy()函数     作为第一个参数,备注字典作为第二个参数。

但是改变并不能解决问题,而是一种更具结构性的解决方案 将对注释将要应用的内容有明确的定义,并且 取消merge_comments。那应该 包括如下拆分多行注释:

# this documents has some non-trivial
# comment lines

# first item follows
- 42
# end of first item

# second item follows
- 196
# end of second item

# final comment of the document

当前,以上内容将加载三个(多行)注释,但是IMO 最好将其解释为六个评论。的 主要任务是仅使用空行来拆分这些注释,而不解释注释的含义。

另外,在节点分配中也可以考虑注释的缩进级别。