2013-01-09 17 views
13

Mam listę słowników, które chcą serializacji:Formatowanie PyYAML dump() Wyjście

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) 

wywołuje następujące:

- key_1: value_a 
    key_2: value_b 
- key_1: value_c 
    key_2: value_d 
(...) 
- key_1: value_x 
    key_2: value_y 

Ale chciałbym uzyskać to:

- 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 mówi o dump() argumenty bardzo krótko i nie wydaje się, aby hAV cokolwiek na ten konkretny temat.

Ręczne edytowanie pliku w celu dodania nowych linii poprawia znacznie czytelność, a struktura nadal ładuje się dobrze, ale nie mam pojęcia, jak utworzyć metodę zrzutów.

A ogólnie, czy istnieje sposób na uzyskanie większej kontroli nad formatowaniem wyjściowym poza prostym wcięciem?

Odpowiedz

11

Nie ma łatwy sposób to zrobić z biblioteki (obiekty węzeł w YAML drzewa składni przegubowe są pasywne i nie może emitować te informacje), więc skończyło się

stream = yaml.dump(list_of_dicts, default_flow_style = False) 
file.write(stream.replace('\n- ', '\n\n- ')) 
+1

Dzięki! Musiał użyć czegoś podobnego do formatowania list. PyYAML nie wstawia wcięcia przed '-', podczas gdy biblioteka zużywająca YAML, której używamy, oczekiwała tam pewnego wcięcia. Tak więc musieliśmy zrobić 'replace ('-', '-')' – Andrei

+0

Ten węzeł jest pasywny jest prawdziwy, ale nie ma znaczenia, ponieważ węzły nie emitują żadnych innych informacji (np. 'ScalarNode's nie emitują własnej wartości)."Emiter" otrzymuje wartość węzła (gdy jest to właściwe) i emituje go, a jeśli załączysz dodatkowe informacje o węzłach i ulepszysz odpowiednie metody emitera, aby obsłużyć te dodatkowe informacje (tak jak robię to w 'ruamel.yaml'), to absolutnie nie ma potrzeby robienia tego rodzaju, grubego, opartego na ciągach przetwarzania końcowego. – Anthon

+0

@Andrei Z ['ruamel.yaml'] (https://pypi.python.org/pypi/ruamel.yaml) możesz ustawić' yaml.indent (sequence = 3, offset = 1) 'i uzyskać te wyniki bez przetwarzanie końcowe. – Anthon

0

natomiast jej trochę klunky Miałem ten sam cel, co OP. Rozwiązałem go przez instacji 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) 

to nazwać tak:

print dump(python_dict, default_flow_style=False, width=79, Dumper=MyDumper) 
1

dokumentacja PyYAML mówi tylko o dump() argumenty krótko, bo nie ma wiele do powiedzenia. Tego rodzaju kontrola nie jest zapewniana przez PyYAML.

Aby umożliwić zachowanie takich pustych (i komentarzy) wierszy w załadowanym YAML, zacząłem rozwijać bibliotekę ruamel.yaml, nadzbiór zablokowanego PyYAML, z kompatybilnością YAML 1.2, poprawiono wiele funkcji i naprawiono błędy. Z ruamel.yaml można zrobić:

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) 

i uzyskać wyjście dokładnie taki sam jak ciąg wejściowy (w tym komentarzu).

Można także zbudować wyjście, które chcesz od podstaw:

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) 

Konwersja za pomocą yaml.seq() konieczne jest stworzenie obiektu, który umożliwia mocowanie pustych linii poprzez wyróżnikiem.

Biblioteka umożliwia również zachowanie/łatwą konfigurację cudzysłowów i literalnego stylu na łańcuchach, format int (hex, ósemkowy, binarny) i floats. Oprócz oddzielnej specyfikacji wcięć dla mapowań i sekwencji (chociaż nie dla pojedynczych mapowań lub sekwencji).