为*未*通过 RoundTripLoader 加载的数据结构生成注释?

Generating comments for a data structure that *wasn't* loaded via RoundTripLoader?

我有一个数据结构,我想向其添加注释,然后将其转换为 YAML。

我想避免将数据结构输出为 YAML 并使用 RoundTripLoader 将其加载回来。

有没有办法将我的数据结构转换为支持 ruamel.yaml 评论界面的数据结构?

有一种方法,尽管不能保证其接口稳定。 因此,由于缺乏文档,查看 round_trip_loading() 预期输出的表示或其中的一小部分样本通常会有所帮助。

您必须意识到注释附加到结构化节点(映射和序列)的表示形式的特殊版本。对于将 safe_load() 作为 Python dict 的映射,这是一个 CommentedMap() 而对于一个序列,它将加载为 Python list, 这是 CommentedSeq().

这两个 类 都可以有一个 .ca 属性保存可能出现在结构节点之前的注释,如 end-of-line-comments 在 key/value 对之后。项目,在 key-value 对或项目之间的单独一行上,并在节点的末尾。

这意味着您必须转换任何需要注释的 dictlist(这可以完成 automatically/recursively 例如通过例程 comment_prep()) , 然后找到正确的点和方式来附加评论。 由于评论操作例程尚未稳定下来,请确保将您的评论添加例程包装起来,以便在它们发生更改时获得更新的单一位置。

import sys
from ruamel.yaml import round_trip_dump as rtd
from ruamel.yaml.comments import CommentedMap, CommentedSeq

# please note that because of the dict the order of the keys is undetermined
data = dict(a=1, b=2, c=['x', 'y', dict(k='i', l=42, m='∞')])

rtd(data, sys.stdout)
print('-' * 30)


def comment_prep(base):
    """replace all dict with CommentedMap and list with CommentedSeq"""
    if isinstance(base, dict):
        ret_val = CommentedMap()
        for key in sorted(base):  # here we force sorted order
            ret_val[key] = comment_prep(base[key])
        return ret_val
    if isinstance(base, list):
        ret_val = CommentedSeq()
        for item in base:
            ret_val.append(comment_prep(item))
        return ret_val
    return base

data = comment_prep(data)
data['c'][2].yaml_add_eol_comment('# this is the answer', key='l', column=15)
rtd(data, sys.stdout)

给出:

c:
- x
- y
- k: i
  m: ∞
  l: 42
b: 2
a: 1
------------------------------
a: 1
b: 2
c:
- x
- y
- k: i
  l: 42        # this is the answer
  m: ∞

文件 test_comment_manipulation.py 有更多示例,是一个值得关注的好地方(随着界面的变化,该文件中的测试也会发生变化)。