Форматирование вывода дампа PyYAML()
У меня есть список словарей, которые я хочу сериализовать:
list_of_dicts = [ { 'key_1': 'value_a', 'key_2': 'value_b'},
{ 'key_1': 'value_c', 'key_2': 'value_d'},
...
{ 'key_1': 'value_x', 'key_2': 'value_y'} ]
yaml.dump(list_of_dicts, file, default_flow_style = False)
выдает следующее:
- key_1: value_a
key_2: value_b
- key_1: value_c
key_2: value_d
(...)
- key_1: value_x
key_2: value_y
Но я хотел бы получить следующее:
- key_1: value_a
key_2: value_b
<-|
- key_1: value_c |
key_2: value_d | empty lines between blocks
(...) |
<-|
- key_1: value_x
key_2: value_y
PyYAML documentation говорит о аргументах dump()
очень кратко и, похоже, ничего не имеет на эту тему.
Редактирование файла вручную для добавления новых строк улучшает читаемость довольно много, и структура по-прежнему загружается сразу после этого, но я понятия не имею, как создать метод дампа.
И вообще, есть ли способ иметь больший контроль над форматированием вывода, кроме простого отступа?
Ответы
Ответ 1
Нет простого способа сделать это с помощью библиотеки (Node объекты в дереве синтаксиса дампера yaml пассивны и не могут испускать эту информацию), поэтому я закончил с
stream = yaml.dump(list_of_dicts, default_flow_style = False)
file.write(stream.replace('\n- ', '\n\n- '))
Ответ 2
Документация PyYAML кратко говорит о аргументах dump()
, потому что говорить нечего. Этот вид управления не предоставляется PyYAML.
Чтобы обеспечить сохранение таких пустых (и комментариев) строк в загружаемом YAML, я начал разработку библиотеки ruamel.yaml
, надмножество застопоренного PyYAML с совместимостью с YAML 1.2, добавлено много функций и исправлены ошибки. С помощью ruamel.yaml
вы можете:
import sys
import ruamel.yaml
yaml_str = """\
- key_1: value_a
key_2: value_b
- key_1: value_c
key_2: value_d
- key_1: value_x # a few before this were ellipsed
key_2: value_y
"""
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
и получить вывод точно так же, как и входная строка (включая комментарий).
Вы также можете создать вывод, который вы хотите с нуля:
import sys
import ruamel.yaml
yaml = ruamel.yaml.YAML()
list_of_dicts = yaml.seq([ { 'key_1': 'value_a', 'key_2': 'value_b'},
{ 'key_1': 'value_c', 'key_2': 'value_d'},
{ 'key_1': 'value_x', 'key_2': 'value_y'} ])
for idx in range(1, len(list_of_dicts)):
list_of_dicts.yaml_set_comment_before_after_key(idx, before='\n')
ruamel.yaml.comments.dump_comments(list_of_dicts)
yaml.dump(list_of_dicts, sys.stdout)
Преобразование с использованием yaml.seq()
необходимо для создания объекта, который позволяет привязывать пустые строки к специальным атрибутам.
Библиотека также позволяет сохранять/легко устанавливать кавычки и буквенный стиль в строках, формат int (шестнадцатеричный, восьмеричный, двоичный) и поплавки. А также отдельная спецификация отступа для сопоставлений и последовательностей (хотя и не для отдельных отображений или последовательностей).
Ответ 3
В то время как его маленький klunky, я имел ту же цель, что и OP.
Я решил это путем подкласса yaml.Dumper
from yaml import Dumper
class MyDumper(Dumper):
def write_indent(self):
indent = self.indent or 0
if not self.indention or self.column > indent \
or (self.column == indent and not self.whitespace):
self.write_line_break()
##########$#######################################
# On the first level of indentation, add an extra
# newline
if indent == 2:
self.write_line_break()
##################################################
if self.column < indent:
self.whitespace = True
data = u' '*(indent-self.column)
self.column = indent
if self.encoding:
data = data.encode(self.encoding)
self.stream.write(data)
Вы называете это следующим образом:
print dump(python_dict, default_flow_style=False, width=79, Dumper=MyDumper)