是的,這是可能的,因爲你可以通過做一個來回檢查:
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
s,這你print(type(data['a'])
檢查:這是一個CommentedMap
(從ruamel.yaml.comment.py
)。對於屬性_yaml_comment
的a
掛起的價值,你可以通過屬性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
。
沒有「幫手」程序來創建這樣一個評論,但通過觀察CommentedMap
和它的基類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
?)並嘗試在輸出期間確定此值,但流出時您的上下文很少。當然,你可以決定/設置列嵌套級(1
),然後乘以縮進(你給round_trip_dump
之一,默認爲2
)
的意見設施廿四註定保全跳閘,而不是最初修改或插入新的,因此接口不能保證穩定。考慮到這一點,請確保您創建了一個例程或一組圍繞yaml_set_comment_before_key()
的例程,以進行更改,因此如果界面更改,則只有一個模塊可以更新(能夠附加評論的功能不會去走,這樣的方法可能改變但是)
¹也許不是你,而是因爲我的ruamel.yaml作者,我應該能夠找到我的未公開代碼的方式。
非常感謝你@Anthon。但是,您在開始key_comment的行中留下了一條調試線,其中「'e'」應該是'key'。此外,如果您需要空白註釋行,該方法會強制您在行尾添加空白。所以我更喜歡改變它,以便用戶需要在#之後立即指定空格。 –
沒有太多的調試,以及首先獲得的功能,然後將其轉換成一種方法,從而忘記了價值 - >參數轉換。感謝您的支持。我還更新了測試評論,不是空字符串(這會導致異常),但是在換行符之前沒有空格(即直接跟在'#'後面)。感謝您的支持。 – Anthon