简体   繁体   English

如何在Python中为YAML文件添加注释

[英]How can I add a comment to a YAML file in Python

I am writing a YAML file using https://pypi.python.org/pypi/ruamel.yaml 我正在使用https://pypi.python.org/pypi/ruamel.yaml编写YAML文件

The code is like this: 代码是这样的:

import ruamel.yaml
from ruamel.yaml.comments import CommentedSeq

d = {}
for m in ['B1', 'B2', 'B3']:
    d2 = {}
    for f in ['A1', 'A2', 'A3']:
        d2[f] = CommentedSeq(['test', 'test2'])
        if f != 'A2':
            d2[f].fa.set_flow_style()
    d[m] = d2

    with open('test.yml', "w") as f:
        ruamel.yaml.dump(
            d, f, Dumper=ruamel.yaml.RoundTripDumper,
            default_flow_style=False, width=50, indent=8)

I just want to add comment at the top like: 我只是想在顶部添加评论,如:

# Data for Class A

Before the YAML data. 在YAML数据之前。

Within your with block, you can write anything you want to the file. 在您的with块中,您可以将任何想要的内容写入文件。 Since you just need a comment at the top, add a call to f.write() before you call ruamel: 由于您只需要在顶部注释,因此在调用ruamel之前添加对f.write()调用:

with open('test.yml', "w") as f:
    f.write('# Data for Class A\n')
    ruamel.yaml.dump(
        d, f, Dumper=ruamel.yaml.RoundTripDumper,
        default_flow_style=False, width=50, indent=8)

That is possible in principle, because you can round-trip such "start-of-file" comments, but it is not nicely supported in the current ruamel.yaml 0.10 and certainly not when "starting from scratch" (ie no changing an existing file). 原则上这是可能的,因为你可以对这样的“文件开始”注释进行往返,但是在当前的ruamel.yaml 0.10中并没有得到很好的支持,当然也不是“从头开始”(即没有改变现有的)文件)。 At the bottom is an easy an relatively nice solution but I would first like to present an ugly workaround and a step-wise how to get this done. 在底部是一个简单的相对不错的解决方案,但我首先想提出一个丑陋的解决方法,并逐步完成如何完成这项工作。

Ugly : 丑陋的
The ugly way to do this is to just add the comment to the file before you write the YAML data to it. 执行此操作的丑陋方法是在将YAML数据写入文件之前将注释添加到文件中。 That is insert: 那是插入:

f.write('# Data for Class A\n')

just before ruamel.yaml.dump(...) 就在ruamel.yaml.dump(...)之前

Step by step : 一步一步
To insert the comment on the data structure, so the above hack is not necessary, you first need to make sure your d data is a CommentedMap type. 要在数据结构上插入注释,因此上述hack不是必需的,首先需要确保您的d数据是CommentedMap类型。 If you compare the difference of that d variable with one that has a the comment by loading the commented YAML back into c 如果通过将注释的YAML加载回c比较该d变量与具有注释的变量的差异

import ruamel.yaml
from ruamel.yaml.comments import Comment, CommentedSeq, CommentedMap

d = CommentedMap()             # <<<<< most important
for m in ['B1', 'B2', 'B3']:
    d2 = {}
    for f in ['A1', 'A2', 'A3']:
        d2[f] = CommentedSeq(['test', 'test2'])
        if f != 'A2':
            d2[f].fa.set_flow_style()
    d[m] = d2

yaml_str = ruamel.yaml.dump(d, Dumper=ruamel.yaml.RoundTripDumper,
                            default_flow_style=False, width=50, indent=8)

assert not hasattr(d, Comment.attrib)  # no attribute on the CommentedMap

comment = 'Data for Class A'
commented_yaml_str = '# ' + comment + '\n' + yaml_str
c = ruamel.yaml.load(commented_yaml_str, Loader=ruamel.yaml.RoundTripLoader)
assert hasattr(c, Comment.attrib)  # c has the attribute
print c.ca                         # and this is what it looks like
print d.ca                         # accessing comment attribute creates it empty
assert hasattr(d, Comment.attrib)  # now the CommentedMap has the attribute

This prints: 这打印:

Comment(comment=[None, [CommentToken(value=u'# Data for Class A\n')]],
  items={})
Comment(comment=None,
  items={})

A Comment has an attribute comment that needs to be set to a 2 element list that consist of the EOL comment (always only one) and a list of preceding line comments (in the form of CommentTokens ) Comment具有属性comment ,需要将其设置为包含EOL注释(始终只有一个)的2元素列表和前一行注释列表(以CommentTokens的形式)

To create a CommentToken you need a (fake) StartMark that tells which column it starts: 要创建CommentToken,您需要一个(假的)StartMark来告诉它启动哪个列:

from ruamel.yaml.error import StreamMark
start_mark = StreamMark(None, None, None, 0, None, None)  # column 0

Now you can create the token: 现在您可以创建令牌:

from ruamel.yaml.tokens import CommentToken

ct = CommentToken('# ' + comment + '\n', start_mark, None)

Assign the token as the first element of the preceding list on your CommentedMap: 将令牌指定为CommentedMap上前面列表的第一个元素:

d.ca.comment = [None, [ct]]
print d.ca   # in case you want to check

gives you: 给你:

Comment(comment=[None, [CommentToken(value='# Data for Class A\n')]],
  items={})

And finally: 最后:

print ruamel.yaml.dump(d, Dumper=ruamel.yaml.RoundTripDumper)  

gives: 得到:

# Data for Class A
B1:
        A1: [test, test2]
        A3: [test, test2]
        A2:
        - test
        - test2
B2:
        A1: [test, test2]
        A3: [test, test2]
        A2:
        - test
        - test2
B3:
        A1: [test, test2]
        A3: [test, test2]
        A2:
        - test
        - test2

Of course you don't need to create the c object, that is just for illustration. 当然,您不需要创建c对象,这只是为了说明。

What you should use : To make the whole exercise somewhat easier you can just forget about the details and patch in the following method to CommentedBase once: 您应该使用的内容 :为了使整个练习更容易一些,您可以忘记细节并在以下方法中对CommentedBase一次修补:

from ruamel.yaml.comments import CommentedBase

def set_start_comment(self, comment, indent=0):
    """overwrites any preceding comment lines on an object
    expects comment to be without `#` and possible have mutlple lines
    """
    from ruamel.yaml.error import StreamMark
    from ruamel.yaml.tokens import CommentToken
    if self.ca.comment is None:
        pre_comments = []
        self.ca.comment = [None, pre_comments]
    else:
        pre_comments = self.ca.comments[1]
    if comment[-1] == '\n':
        comment = comment[:-1]  # strip final newline if there
    start_mark = StreamMark(None, None, None, indent, None, None)
    for com in comment.split('\n'):
        pre_comments.append(CommentToken('# ' + com + '\n', start_mark, None))

if not hasattr(CommentedBase, 'set_start_comment'): # in case it is there
    CommentedBase.set_start_comment = set_start_comment

and then just do: 然后就是:

d.set_start_comment('Data for Class A')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM