Это в принципе возможно, потому что вы можете туда-обратно, например «запуск из файла» комментарии, но он не очень хорошо поддерживается в текущем файле ruamel.yaml 0.10 и, конечно, не «начинать с нуля» (т. е. не изменять существующий файл). В нижней части это легкое относительно хорошее решение, но сначала я хотел бы представить уродливое обходное решение и поэтапно, как это сделать.
Гадкий:
Уродливый способ сделать это просто добавить свой комментарий к файлу, прежде чем записать данные YAML к нему. То есть вставка:
f.write('# Data for Class A\n')
непосредственно перед ruamel.yaml.dump(...)
Шаг за шагом:
Чтобы вставить комментарий о структуре данных, поэтому приведенные выше хак не является необходимым, вы первый необходимо, чтобы убедиться, ваши данные d
- это тип CommentedMap
.Если вы сравните разницу этой d
переменной с одним, который имеет комментарий, загрузив комментируемой YAML обратно в c
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
Печатается:
Comment(comment=[None, [CommentToken(value=u'# Data for Class A\n')]],
items={})
Comment(comment=None,
items={})
Comment
имеет атрибут comment
, который необходимо должен быть установлен в список из 2 элементов, который состоит из комментария EOL (всегда только один) и списка предыдущих комментариев строки (в форме CommentTokens
)
Для создания CommentToken вам нужен (поддельный) StartMark, который говорит, какой столбец начинается:
from ruamel.yaml.error import Mark
start_mark = Mark(None, None, None, 0, None, None) # column 0
Теперь вы можете создать маркер:
from ruamel.yaml.tokens import CommentToken
ct = CommentToken('# ' + comment + '\n', start_mark, None)
Назначьте маркер в качестве первого элемента предыдущего список на вашем CommentedMap:
d.ca.comment = [None, [ct]]
print d.ca # in case you want to check
дает:
Comment(comment=[None, [CommentToken(value='# Data for Class A\n')]],
items={})
И наконец:
print ruamel.yaml.dump(d, Dumper=ruamel.yaml.RoundTripDumper)
дает:
# 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
Конечно, вам не нужно, чтобы создать c
объект, то есть только для иллюстрации.
Что вы должны использовать: Для того, чтобы сделать все упражнение несколько легче, вы можете просто забыть о деталях и пластыря в следующем методе 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 Mark
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 = Mark(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
, а затем просто сделать:
d.set_start_comment('Data for Class A')
Это было легко :) – user3214546