如何使用 ruamel.yaml 在 Python 中的 YAML 中插入注释行?

2023-11-21

我有一个像这样的结构,我想使用添加注释行ruamel.yaml:

xyz:
  a: 1    # comment 1
  b: 2

test1:
  test2:
    test3: 3

现在,我想插入注释行(不是 eol_comments),使其看起来像这样:

xyz:
  a: 1    # comment 1
  b: 2

# before test1 (top level)
test1:
  # before test2
  test2:
    # after test2
    test3: 3

我知道,我可以使用添加 eol_commentsruamel.yaml,但我没有找到添加整个注释行的方法。


确实没有这个功能ruamel.yaml<=0.12.18在键之前的行上插入注释,但有一个函数可以在结构的开头设置注释:.yaml_set_start_comment。这样您就可以设置要添加的三个注释中的两个:

import sys
import ruamel.yaml

yaml_str = """\
xyz:
  a: 1    # comment 1
  b: 2

test1:
  test2:
    test3: 3
"""

data = ruamel.yaml.round_trip_load(yaml_str)
data['test1'].yaml_set_start_comment('before test2', indent=2)
data['test1']['test2'].yaml_set_start_comment('after test2', indent=4)
ruamel.yaml.round_trip_dump(data, sys.stdout)

gives:

xyz:
  a: 1    # comment 1
  b: 2

test1:
  # before test2
  test2:
    # after test2
    test3: 3

实际上有一个“注释”,由值之间的空行组成xyz and test1,但是如果您将注释附加到该结构,然后在之前插入一个新键test1事情并没有如你所愿。因此要做的就是在 key 之前明确插入注释test1。您可以往返加载您的预期输出以查看内部Comment应该看起来像:

yaml_str_out = """\
xyz:
  a: 1    # comment 1
  b: 2

# before test1 (top level)
test1:
  # before test2
  test2:
    # before test3
    test3: 3
"""
test = ruamel.yaml.round_trip_load(yaml_str_out)
print(test.ca)

给出(将其包装起来以便于查看):

Comment(comment=None,
        items={'test1': [None, 
                        [CommentToken(value='# before test1 (top level)\n')], 
                        None, 
                        [CommentToken(value='# before test2\n')]]})

如你所见# before test2被认为是键后的注释。 并在做test['test1'].yaml_set_start_comment('xxxxx', indent=2)将要 与关联的评论没有任何影响test1否决了这一点并且# xxxxx will not出现在转储中。

有了这些信息和一些背景知识,我改编了一些代码yaml_set_start_comment()(假设原始进口和yaml_str):

def yscbak(self, key, before=None, indent=0, after=None, after_indent=None):
    """
    expects comment (before/after) to be without `#` and possible have multiple lines
    """
    from ruamel.yaml.error import Mark
    from ruamel.yaml.tokens import CommentToken

    def comment_token(s, mark):
        # handle empty lines as having no comment
        return CommentToken(('# ' if s else '') + s + '\n', mark, None)

    if after_indent is None:
        after_indent = indent + 2
    if before and before[-1] == '\n':
        before = before[:-1]  # strip final newline if there
    if after and after[-1] == '\n':
        after = after[:-1]  # strip final newline if there
    start_mark = Mark(None, None, None, indent, None, None)
    c = self.ca.items.setdefault(key, [None, [], None, None])
    if before:
        for com in before.split('\n'):
            c[1].append(comment_token(com, start_mark))
    if after:
        start_mark = Mark(None, None, None, after_indent, None, None)
        if c[3] is None:
            c[3] = []
        for com in after.split('\n'):
            c[3].append(comment_token(com, start_mark))

if not hasattr(ruamel.yaml.comments.CommentedMap, 
               'yaml_set_comment_before_after_key'):
    ruamel.yaml.comments.CommentedMap.yaml_set_comment_before_after_key = yscbak


data = ruamel.yaml.round_trip_load(yaml_str)
data.yaml_set_comment_before_after_key('test1', 'before test1 (top level)',
                                       after='before test2', after_indent=2)
data['test1']['test2'].yaml_set_start_comment('after test2', indent=4)
ruamel.yaml.round_trip_dump(data, sys.stdout)

and get:

xyz:
  a: 1    # comment 1
  b: 2

# before test1 (top level)
test1:
  # before test2
  test2:
    # after test2
    test3: 3

测试与hasattr是为了确保在添加这样的函数时不会覆盖它ruamel.yaml

顺便说一句:所有注释都是 YAML 中的行尾注释,其中一些注释之前可能只是有效的 YAML。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 ruamel.yaml 在 Python 中的 YAML 中插入注释行? 的相关文章

随机推荐