在 Ruamel.yaml 中的键前插入评论
Insert a comment before a key in Ruamel.yaml
我正在使用 Ruamel Python 库以编程方式编辑人工编辑的 YAML 文件。
我很难理解如何将评论插入结构化数据。
我有一些数据:
a:
b: banana
c: apple
d: orange
我想添加一条评论和一个新密钥:
a:
b: banana
c: apple
d: orange
# This is my comment
e: pear
是否可以使用 ruamel.yaml
执行此操作,如果可以,如何操作?
是的,这是可能的,因为您可以通过往返检查:
import sys
import ruamel.yaml
with open('your_input.yaml') as fp:
data = ruamel.yaml.round_trip_load(yaml_str)
ruamel.yaml.round_trip_dump(data, sys.stdout)
打印的输出将与您的输入相匹配,因此注释会以某种方式插入到结构的 data
层次结构中,保存并在转储时写出。
在 ruamel.yaml
中,注释附加到 lists
或 dict
的包装器 classes 中,您可以使用 print(type(data['a'])
检查:它是一个CommentedMap
(来自 ruamel.yaml.comment.py
)。 a
的值的注释信息挂在属性 _yaml_comment
上,您可以通过 属性 ca
:
访问
cm = data['a']
print(cm.ca)
给出:
items={'e': [None, [CommentToken(value='# This is my comment\n')], None, None]})
这表明评论与评论后面的键 e
相关联。不幸的是 CommentToken
不能像它所表示的那样通过调用它来创建(即 CommentToken(value='# This is my comment\n')
),它需要更多的工作,因为它至少需要一个开始 Mark
.
没有 "helper" 例程来创建这样的评论,但是通过查看 CommentedMap
及其基数 class CommentedBase
您可以得出以下结果 ¹ :
import sys
import ruamel.yaml
if not hasattr(ruamel.yaml.comments.CommentedMap, "yaml_set_comment_before_key"):
def my_yaml_set_comment_before_key(self, key, comment, column=None,
clear=False):
"""
append comment to list of comment lines before key, '# ' is inserted
before the comment
column: determines indentation, if not specified take indentation from
previous comment, otherwise defaults to 0
clear: if True removes any existing comments instead of appending
"""
key_comment = self.ca.items.setdefault(key, [None, [], None, None])
if clear:
key_comment[1] = []
comment_list = key_comment[1]
if comment:
comment_start = '# '
if comment[-1] == '\n':
comment = comment[:-1] # strip final newline if there
else:
comment_start = '#'
if column is None:
if comment_list:
# if there already are other comments get the column from them
column = comment_list[-1].start_mark.column
else:
column = 0
start_mark = ruamel.yaml.error.Mark(None, None, None, column, None, None)
comment_list.append(ruamel.yaml.tokens.CommentToken(
comment_start + comment + '\n', start_mark, None))
return self
ruamel.yaml.comments.CommentedMap.yaml_set_comment_before_key = \
my_yaml_set_comment_before_key
使用此方法扩展 CommentedMap
,然后您可以执行以下操作:
yaml_str = """\
a:
b: banana
c: apple
d: orange
e: pear
"""
data = ruamel.yaml.round_trip_load(yaml_str)
cm = data['a']
cm.yaml_set_comment_before_key('e', "This is Alex' comment", column=2)
cm.yaml_set_comment_before_key('e', 'and this mine')
ruamel.yaml.round_trip_dump(data, sys.stdout)
得到:
a:
b: banana
c: apple
d: orange
# This is Alex' comment
# and this mine one
e: pear
除非你看评论,否则无法查询cm
是哪一栏
注释应该在其中,以使其与键 e
对齐(该列是在写出数据结构时确定的)。您可能想存储一个特殊值 (-1
?) 并尝试在输出期间确定它,但在流出时您几乎没有上下文。您当然可以将列 determine/set 设置为嵌套级别 (1
) 并将其乘以缩进(您给 round_trip_dump
的缩进,默认为 2
)
评论功能是来回保存的,最初不是为了修改或插入新的,所以不保证界面稳定。考虑到这一点,请确保围绕 yaml_set_comment_before_key()
创建单个例程或一组例程以进行更改,因此如果接口更改(能够附加一个评论不会消失,但是这样做的方法可能会改变)
¹ 也许不是你,但由于我是 ruamel.yaml 的作者,我应该能够在文档不足的代码中找到我的方法。
我正在使用 Ruamel Python 库以编程方式编辑人工编辑的 YAML 文件。
我很难理解如何将评论插入结构化数据。
我有一些数据:
a:
b: banana
c: apple
d: orange
我想添加一条评论和一个新密钥:
a:
b: banana
c: apple
d: orange
# This is my comment
e: pear
是否可以使用 ruamel.yaml
执行此操作,如果可以,如何操作?
是的,这是可能的,因为您可以通过往返检查:
import sys
import ruamel.yaml
with open('your_input.yaml') as fp:
data = ruamel.yaml.round_trip_load(yaml_str)
ruamel.yaml.round_trip_dump(data, sys.stdout)
打印的输出将与您的输入相匹配,因此注释会以某种方式插入到结构的 data
层次结构中,保存并在转储时写出。
在 ruamel.yaml
中,注释附加到 lists
或 dict
的包装器 classes 中,您可以使用 print(type(data['a'])
检查:它是一个CommentedMap
(来自 ruamel.yaml.comment.py
)。 a
的值的注释信息挂在属性 _yaml_comment
上,您可以通过 属性 ca
:
cm = data['a']
print(cm.ca)
给出:
items={'e': [None, [CommentToken(value='# This is my comment\n')], None, None]})
这表明评论与评论后面的键 e
相关联。不幸的是 CommentToken
不能像它所表示的那样通过调用它来创建(即 CommentToken(value='# This is my comment\n')
),它需要更多的工作,因为它至少需要一个开始 Mark
.
没有 "helper" 例程来创建这样的评论,但是通过查看 CommentedMap
及其基数 class CommentedBase
您可以得出以下结果 ¹ :
import sys
import ruamel.yaml
if not hasattr(ruamel.yaml.comments.CommentedMap, "yaml_set_comment_before_key"):
def my_yaml_set_comment_before_key(self, key, comment, column=None,
clear=False):
"""
append comment to list of comment lines before key, '# ' is inserted
before the comment
column: determines indentation, if not specified take indentation from
previous comment, otherwise defaults to 0
clear: if True removes any existing comments instead of appending
"""
key_comment = self.ca.items.setdefault(key, [None, [], None, None])
if clear:
key_comment[1] = []
comment_list = key_comment[1]
if comment:
comment_start = '# '
if comment[-1] == '\n':
comment = comment[:-1] # strip final newline if there
else:
comment_start = '#'
if column is None:
if comment_list:
# if there already are other comments get the column from them
column = comment_list[-1].start_mark.column
else:
column = 0
start_mark = ruamel.yaml.error.Mark(None, None, None, column, None, None)
comment_list.append(ruamel.yaml.tokens.CommentToken(
comment_start + comment + '\n', start_mark, None))
return self
ruamel.yaml.comments.CommentedMap.yaml_set_comment_before_key = \
my_yaml_set_comment_before_key
使用此方法扩展 CommentedMap
,然后您可以执行以下操作:
yaml_str = """\
a:
b: banana
c: apple
d: orange
e: pear
"""
data = ruamel.yaml.round_trip_load(yaml_str)
cm = data['a']
cm.yaml_set_comment_before_key('e', "This is Alex' comment", column=2)
cm.yaml_set_comment_before_key('e', 'and this mine')
ruamel.yaml.round_trip_dump(data, sys.stdout)
得到:
a:
b: banana
c: apple
d: orange
# This is Alex' comment
# and this mine one
e: pear
除非你看评论,否则无法查询cm
是哪一栏
注释应该在其中,以使其与键 e
对齐(该列是在写出数据结构时确定的)。您可能想存储一个特殊值 (-1
?) 并尝试在输出期间确定它,但在流出时您几乎没有上下文。您当然可以将列 determine/set 设置为嵌套级别 (1
) 并将其乘以缩进(您给 round_trip_dump
的缩进,默认为 2
)
评论功能是来回保存的,最初不是为了修改或插入新的,所以不保证界面稳定。考虑到这一点,请确保围绕 yaml_set_comment_before_key()
创建单个例程或一组例程以进行更改,因此如果接口更改(能够附加一个评论不会消失,但是这样做的方法可能会改变)
¹ 也许不是你,但由于我是 ruamel.yaml 的作者,我应该能够在文档不足的代码中找到我的方法。