【问题标题】:Python Ruamel YAML - how to get comments of merged portionsPython Ruamel YAML - 如何获取合并部分的评论
【发布时间】:2020-07-23 19:47:36
【问题描述】:

如果我加载这个示例 YAML 文件:

aliases:
  - &a1
    b1: 5         # Comment for b1=5
    c1: 3         # Comment for c1=3

model:
  obj1:
    <<: *a1
    d1: 7         # Comment for d1=7
  obj2:
    *a1
  obj3:
    *a1

使用此代码:

import ruamel.yaml as yaml

with open("test.yaml") as fp:
    d = yaml.load(fp, yaml.RoundTripLoader)

def showcmts(d):
    for k,v in d.items():
        print("Key {} has {}".format(k, (d.ca.items[k][2] if k in d.ca.items and d.ca.items[k][2] is not None else "no comment")))

print("Model obj1 contents and comments are:")
showcmts(d["model"]["obj1"])
print("Model obj2 contents and comments are:")
showcmts(d["model"]["obj2"])
print("Model obj3 contents and comments are:")
showcmts(d["model"]["obj3"])

我得到这个输出:

Model obj1 contents and comments are:
Key d1 has CommentToken('# Comment for d1=7\n', line: 8, col: 18)
Key b1 has no comment
Key c1 has no comment
Model obj2 contents and comments are:
Key b1 has CommentToken('# Comment for b1=5\n', line: 2, col: 18)
Key c1 has CommentToken('# Comment for c1=3\n\n', line: 3, col: 18)
Model obj3 contents and comments are:
Key b1 has CommentToken('# Comment for b1=5\n', line: 2, col: 18)
Key c1 has CommentToken('# Comment for c1=3\n\n', line: 3, col: 18)

如何获取与obj1/b1obj1/c1 关联的cmets? cmets 正在加载并正确读取 obj2/b1 等,但我需要它们也可以用于obj1/b1 等。

【问题讨论】:

  • 您从哪里获得使用 d = yaml.load(fp, yaml.RoundTripLoader) 加载 YAML 的示例?您应该使用几年前推出的新 API(使用 YAML() 实例)。
  • 好问题 - 我看到当前版本的文档引用了 YAML() 实例方法。这段代码只有几个月的历史。我相信我从stackoverflow.com/questions/52043027/… 的示例开始,然后在寻找修复导出后添加了 RoundTripLoader 位。我将更新 YAML() 方法的代码。
  • 该示例已经使用了新的 API。我只是好奇我是否可以更新(或建议更新)一些示例以确保人们从新 API 开始(与旧 API 相比,它允许更多控制,尤其是在输出方面)

标签: ruamel.yaml


【解决方案1】:

ruamel.yaml,使用往返加载器/转储器,并没有真正合并映射。它让他们 单独的,因此它们可以作为单独的实体转储,但提供特殊版本的 对从“合并映射”构造的对象进行键/值访问,就好像那是一个字典一样。

所以你需要做两件事:

  • 区分真实键和合并键
  • 访问合并键的注释

请注意,要这样做,您需要访问未记录的内部信息 可能会更改,恕不另行通知。将您的生产代码固定到特定的 YAML 版本 您正在开发的产品。

from pathlib import Path
import ruamel.yaml


def showcmts(d):
    def pkc(k, d):
        print("Key {} has {}".format(k, (d.ca.items[k][2] if k in d.ca.items and d.ca.items[k][2] is not None else "no comment")))

    for k in d:
        if k in d._ok:  # Own Keys i.e. not merged-in
            pkc(k, d)
            continue
        for pos, merge in d.merge:
            if k in merge._ok:
                pkc(k, merge)
                break
    
yaml = ruamel.yaml.YAML()
d = yaml.load(Path('test.yaml'))

print("Model obj1 contents and comments are:")
showcmts(d["model"]["obj1"])
print("Model obj2 contents and comments are:")
showcmts(d["model"]["obj2"])
print("Model obj3 contents and comments are:")
showcmts(d["model"]["obj3"])

给出:

Model obj1 contents and comments are:
Key d1 has CommentToken('# Comment for d1=7\n', line: 8, col: 18)
Key b1 has CommentToken('# Comment for b1=5\n', line: 2, col: 18)
Key c1 has CommentToken('# Comment for c1=3\n\n', line: 3, col: 18)
Model obj2 contents and comments are:
Key b1 has CommentToken('# Comment for b1=5\n', line: 2, col: 18)
Key c1 has CommentToken('# Comment for c1=3\n\n', line: 3, col: 18)
Model obj3 contents and comments are:
Key b1 has CommentToken('# Comment for b1=5\n', line: 2, col: 18)
Key c1 has CommentToken('# Comment for c1=3\n\n', line: 3, col: 18)

【讨论】:

  • 效果很好,谢谢。是否值得 mu 添加功能请求票证以使 cmets 对象以与数据对象相同的方式工作(因此不需要此代码)?
  • ruamel.yaml 如果用于往返,则保留 cmets。 cmets 是供人类使用的,用于理解实际数据。如果计算机程序应该知道 cmets 中的某些内容,则数据不完整和/或定义不灵活。鉴于此前提,如果您需要比较数据和 cmets,IMO 您正在滥用该库来补偿错误/不完整的数据。因此,实例化类中的扩展不太可能促进这一点(因此我建议固定使用的 ruamel.yaml 版本)。
猜你喜欢
  • 2019-04-27
  • 2017-09-21
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
  • 2013-10-02
相关资源
最近更新 更多