2016-11-23 2 views
2

Ich habe eine .yaml-Datei, die ich mit einem Python-Code aktualisieren möchte. Sagen wir es so etwas wie das aussieht:Ändern eines Wertes in einer YAML-Datei mit Python

state: 'present' 

Ich möchte einen Code haben, der den Zustand ändert und speichert die Datei. Ich versuche, mit so etwas wie dieses und fehlschlagen:

def set_state(state): 
    with open("file_to_edit.yaml", 'rw') as f: 
     doc = yaml.load(f) 
    doc['state'] = state 
    yaml.dump(f) 

Ich bin mit dem ‚yaml‘ Paket für Python.

+0

Erhalten Sie einen Fehler irgendeiner Art? – usr2564301

+1

Nein, es hat nur nichts geändert –

+0

Es scheint einfach nicht aus irgendeinem Grund in die Datei zu schreiben –

Antwort

4

Das Problem ist, dass yaml.dump eigentlich nicht in eine Datei schreiben. Stattdessen it returns the modified YAML as a string, wenn Sie es nicht direkt in die Datei schreiben.

Folgendes sollte funktionieren:

def set_state(state): 
    with open('file_to_edit.yaml') as f: 
     doc = yaml.load(f) 

    doc['state'] = state 

    with open('file_to_edit.yaml', 'w') as f: 
     yaml.dump(doc, f) 
+1

Bam, das macht den Trick! Danke vielmals! –

+0

Wie nennt man eine YAML-Struktur? 'dump()' gibt eine Zeichenkette zurück (die ein YAML-Dokument enthält), außer Sie geben einen 'stream' Parameter an (was Sie tun sollten). Das Schreiben dieses zurückgegebenen Strings in eine Datei ist eine ineffiziente Art und Weise der Verwendung von "yaml.dump()" und schlechten Ratschlägen. – Anthon

1

Meine Vermutung ist, dass Sie nicht richtig einrücken, da Ihre Funktion in ihrem aktuellen Zustand nichts zu tun scheint. Python tut kümmern sich um Einrückung.

Versuchen Sie folgendes:

def set_state(state): 
    with open("file_to_edit.yaml", 'rw') as f: 
     doc = yaml.load(f) 
    doc['state'] = state 
    yaml.dump(f) 
+1

Oh nein, die Einrückung ist in Ordnung .. Ich habe es einfach nicht gut hier eingefügt .. –

0

Sie können folgende versuchen (es erstellt eine neue Datei das Ergebnis zu speichern):

with open("output_file", 'a') as out: 
    with open("input_file", 'r') as f: 
     for line in f: 
      line = re.sub(r"state: present", "state: installed", line) 
      out.write(line) 
+1

Ich bevorzuge die gleiche Datei, aber danke! –

1

etwas anderes Vorher: nie yaml.load() verwenden, wenn Sie muss nicht, wie es grundsätzlich unsicher ist, dies zu tun. Für diese einfache Struktur (ohne Tags) sollten Sie yaml.safe_load() (und die entsprechende safe_dump(), die sich beschweren, wenn Ihre Daten nach dem Dumping nicht sicher sein können) verwenden.

yaml.dump() hat die folgende Signatur:

def dump(documents, stream=None, Dumper=Dumper, 
     default_style=None, default_flow_style=None, 
     canonical=None, indent=None, width=None, 
     allow_unicode=None, line_break=None, 
     encoding='utf-8', explicit_start=None, explicit_end=None, 
     version=None, tags=None) 

Davon wird nur der erste muss gegeben werden, die Ihre doc variabel sein sollte. Wenn Sie keinen Stream angeben, schreibt dump() die Datenstruktur in ein Dateiobjekt im Speicher (wie StringIO) und gibt nach dem Schreiben den Wert als String zurück.

Und obwohl man tun könnte:

with open("file_to_edit.yaml", 'w') as f: 
    f.write(yaml.safe_dump(doc)) 

dies ist ineffizient und zeigt wenig Verständnis dafür, wie yaml.safe_dump() funktioniert.

Wenn Sie die Datei zum Lesen und Schreiben öffnen möchten, müssen Sie sicherstellen, dass Sie beide den Index in den Dateien und den Inhalt abschneiden. Dies ist in der Regel nicht die Mühe wert, so dass es sicherer ist, die Datei zum Schreiben wieder zu öffnen:

def set_state(state): 
    file_name = "file_to_edit.yaml" 
    with open(file_name) as f: 
     doc = yaml.safe_load(f) 
    doc['state'] = state 
    with open(file_name, 'w') as f: 
     yaml.safe_dump(doc, f, default_flow_style=False) 

(natürlich können Sie die Dateinamen eine Variable, wenn Sie Ihnen das Original überschreiben, um sicherzustellen, wollen, so können Sie nicht vertippt es).

Wenn Sie nicht default_flow_style=False angeben, wird die Ausgabe wie folgt aussehen:

{state: deleted} 

Der Ausgang wird nicht enthalten, die überflüssigen Anführungszeichen um present in Ihrer Eingabe. Sie können default_style="'" auch angeben, aber dies wird auch Zitate um state setzen.
Wenn das Verlieren der Anführungszeichen ein Problem ist und Sie möchten, dass die Ausgabe wie die Eingabe aussieht, sollten Sie ruamel.yaml verwenden (Disclaimer, ich bin der Autor dieses Pakets), die die Anführungszeichen für einzelne Strings beibehalten kann, handhabt YAML 1.2 (anstelle von YAML 1.1) und behält Kommentare in Ihrer Datei.

Verwandte Themen