【问题标题】:deepcopy YAML with top-level list comment in Python在 Python 中具有顶级列表注释的 deepcopy YAML
【发布时间】:2019-11-03 15:56:16
【问题描述】:

我正在尝试使用 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")

是否有替代方法可以将加载的带有此类 cmets 的 YAML 转储到多个文件中?

【问题讨论】:

  • 预期目标是什么?您想将完全相同的 YAML 从一个文件复制到另一个文件吗?
  • 我希望能够转储深度复制的 YAML。在我的完整场景中,我在转储它们之前对不同的深层副本执行不同的操作。
  • 深度复制版本的错误(完整堆栈跟踪!)是什么?如果需要获取完整的堆栈跟踪,请删除 try/except。
  • @barny 这里是:pastebin.com/FipNEqqg
  • 将其编辑到您的问题中。

标签: python yaml pyyaml ruamel.yaml


【解决方案1】:

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

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

这是一个权宜之计,但效果很好 如果您将 ruamel.yaml 用于加载-修改-保存的预期目的,但 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。那应该 包括拆分多行 cmets,如下所示:

# 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

目前上述内容将加载三个(多行)cmets,但 IMO 将其解释为六个 cmets 会更合适。这 主要任务是定义拆分此类 cmets 而不解释注释的含义,仅使用空行。

另外,节点分配可能会考虑注释的缩进级别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 2012-01-04
    • 2015-09-08
    • 1970-01-01
    • 2022-09-23
    相关资源
    最近更新 更多