2016-05-10 5 views
1

ich folgende YAML-Datei erhalten möchten:PyYAML, safe_dump Hinzufügen Zeilenumbrüche und Einzüge in die YAML-Datei

--- 
classes: 
    - apache 
    - ntp 

apache::first: 1 
apache::package_ensure: present 
apache::port: 999 
apache::second: 2 
apache::service_ensure: running 

ntp::bla: bla 
ntp::package_ensure: present 
ntp::servers: '-' 

Nach Parsen ich eine solche Ausgabe erhalten:

--- 
apache::first: 1 
apache::package_ensure: present 
apache::port: 999 
apache::second: 2 
apache::service_ensure: running 
classes: 
- apache 
- ntp 
ntp::bla: bla 
ntp::package_ensure: present 
ntp::servers: '-' 

Here, habe ich gefunden, die Eigenschaften, die die Möglichkeit geben, Dokumente zu formatieren. Ich habe versucht, line_break und Einzug, aber es funktioniert nicht.

with open(config['REPOSITORY_PATH'] + '/' + file_name, 'w+') as file: 
      yaml.safe_dump(data_map, file, indent=10, explicit_start=True, explicit_end=True, default_flow_style=False, 
          line_break=1) 
     file.close() 

Bitte, raten Sie mir einfache Vorgehensweise, um die Ausgabe zu stylen.

+0

Sie sollten 'file.close()' nicht explizit aufrufen, das Beenden der with-Anweisung schließt die Datei für Sie (auch wenn eine Ausnahme auftritt) – Anthon

Antwort

1

Das ist in PyYAML nicht möglich. Die Option indent betrifft nur Zuordnungen und keine Sequenzen. PyYAML bewahrt auch nicht die Reihenfolge der Zuordnungsschlüssel beim Runden.

Wenn Sie ruamel.yaml (Dislaimer: Ich bin der Autor dieses Pakets) verwenden, dann genau die gleiche Eingabe immer als Ausgang ist einfach:

import ruamel.yaml 

yaml_str = """\ 
--- 
classes: 
    - apache # keep the indentation 
    - ntp 

apache::first: 1 
apache::package_ensure: present 
apache::port: 999 
apache::second: 2 
apache::service_ensure: running 

ntp::bla: bla 
ntp::package_ensure: present 
ntp::servers: '-' 
""" 

data = ruamel.yaml.round_trip_load(yaml_str) 
res = ruamel.yaml.round_trip_dump(data, indent=4, block_seq_indent=2, 
          explicit_start=True) 
assert res == yaml_str 

Bitte beachten Sie, dass es auch den Kommentar bewahrt ich das addierte erstes Sequenzelement


Sie können dies von „scratch“ bauen, sondern eine neue Zeile hinzuzufügen, ist nicht etwas, für das ein Anruf in ruamel.yaml existiert:

import ruamel.yaml 
from ruamel.yaml.tokens import CommentToken 
from ruamel.yaml.error import Mark 
from ruamel.yaml.comments import CommentedMap, CommentedSeq 


data = CommentedMap() 
data['classes'] = classes = CommentedSeq() 
classes.append('apache') 
classes.append('ntp') 

data['apache::first'] = 1 
data['apache::package_ensure'] = 'present' 
data['apache::port'] = 999 
data['apache::second'] = 2 
data['apache::service_ensure'] = 'running' 
data['ntp::bla'] = 'bla' 
data['ntp::package_ensure'] = 'present' 
data['ntp::servers'] = '-' 


m = Mark(None, None, None, 0, None, None) 
data['classes'].ca.items[1] = [CommentToken('\n\n', m, None), None, None, None] 
#      ^1 is the last item in the list 
data.ca.items['apache::service_ensure'] = [None, None, CommentToken('\n\n', m, None), None] 

res = ruamel.yaml.round_trip_dump(data, indent=4, block_seq_indent=2, 
          explicit_start=True) 
print(res, end='') 

Sie die Newline als Kommentar muss hinzufügen (ohne '# ') bis zum letzten Element vor dem Zeilenumbruch, dh dem letzten Listenelement und dem Zuordnungseintrag apache::service_ensure.


Abgesehen davon sollten Sie sich fragen, ob Sie wirklich wollen PyYAML verwenden, die nur unterstützt (die meisten) YAML 1.1 aus dem Jahr 2005 und nicht die neueste Version von YAML 1.2 aus dem Jahr 2009.

Die Wordpress-Seite verlinkt scheint nicht sehr ernst (es hat nicht einmal den Paketnamen, PyYAML, richtig).

+0

Danke, das möchte ich. In meinem Fall sind die Eingabedaten ein dict generiert aus dem Anfragetext und sieht so aus: '{u'apache :: package_ensure ': u'present', u'apache :: first ': 1, u'ntp :: bla ':' bla ', u'apache :: second': 2, 'classes': [u'apache ', u'ntp'], u'ntp :: package_ensure ': u'present', u'ntp: : servers ':' ',' 'apache :: service_ensure': u'running ', u'apache :: port': 999} '. Gibt es eine Möglichkeit, das gewünschte Format (wie oben) von diesem Diktat zu gewinnen? Oder sollte ich es zusätzlich verarbeiten? –

+0

Alles außer den leeren Zeilen ist trivial. Sie müssen nur eine "CommentedMap" -Instanz erstellen ('from ramel.yaml.comments Import CommentedMap') und die Schlüssel den Schlüsseln in der gewünschten Reihenfolge zuweisen und dann diese Instanz ausgeben. Ich würde in die Details schauen müssen, um die leeren Zeilen hinzuzufügen, aber es ist im Allgemeinen leichter, eine grobe korrekte YAML-Datei zu laden und auszufüllen. Haben Sie immer die gleichen Schlüssel mit unterschiedlichen Werten? Oder zumindest immer 3 Abschnitte, die mit Leerzeile getrennt werden müssen? – Anthon

+0

Der Benutzer generiert die Yaml-Datei über die Benutzeroberfläche, indem er verschiedene Schlüssel und Einstellwerte auswählt. Daher könnten Tasten unterschiedlich sein, und die Nummer des Abschnitts kann auch anders sein (weniger als drei) –