6

次を使用してコメント行を追加したい、このような構造があります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_comments を追加できることはわかってruamel.yamlいますが、コメント行全体を追加する方法が見つかりませんでした。

4

1 に答える 1

8

ruamel.yaml<=0.12.18キーの前の行にコメントを挿入する関数は実際にはありませんが、構造体の先頭にコメントを設定する関数があります: .yaml_set_start_comment. これで、追加したい 3 つのコメントのうち 2 つをすでに設定できます。

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)

与えます:

xyz:
  a: 1    # comment 1
  b: 2

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

実際には、xyzとの値の間に空の行を構成する「コメント」があり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

その情報といくつかの背景知識を使用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)

そして得る:

xyz:
  a: 1    # comment 1
  b: 2

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

でのテストhasattrは、そのような関数が追加されたときに上書きしないことを確認することですruamel.yaml

ところで: すべてのコメントは YAML の行末コメントです。これらのコメントの前に有効な YAML があるだけかもしれません。

于 2016-11-20T15:13:46.233 に答える