2016-01-05 16 views
5

Utilizziamo PyYAML per preparare i file di configurazione per ambienti diversi. Ma i nostri blocchi YAML perdono integrità.È possibile conservare la struttura a blocchi YAML quando si esegue il dumping di un documento analizzato?

Dare input.yml ...

pubkey: | 
    -----BEGIN PUBLIC KEY----- 
    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 
    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 
    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 
    EsUgJHXcpw7OPxRrCQIDAQAB 
    -----END PUBLIC KEY----- 

... l'esecuzione di questo programma utilizzando python3 ...

import yaml 

with open('input.yml', mode='r') as f: 
    parsed = yaml.safe_load(f) 

with open('output.yml', mode='w') as f: 
    yaml.dump(parsed, f) 

... produce questo output.yml ...

pubkey: '-----BEGIN PUBLIC KEY----- 

    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 

    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 

    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 

    EsUgJHXcpw7OPxRrCQIDAQAB 

    -----END PUBLIC KEY----- 

    ' 

È possibile preservare la struttura del mio blocco usando PyYAML?

risposta

5

Sì che è possibile con pyyaml, ma si ha a fornire le proprie versioni migliorate di almeno Scanner, Parser e Constructor che sono utilizzati da safe_load, l'emettitore, Serializzatore e representer utilizzato da discarica, e fornendo una classe spezzata specializzata che conserva informazioni sulla sua formattazione originale.

Questo è parte di ciò che è stato aggiunto al ruamel.yaml (diniego: Io sono l'autore di quel pacchetto), in quanto deriva da PyYAML e mantiene ancora una configurazione simile. Utilizzando ruamel.yaml:

import ruamel.yaml as yaml 

yaml_str = """\ 
pubkey: | 
    -----BEGIN PUBLIC KEY----- 
    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 
    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 
    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 
    EsUgJHXcpw7OPxRrCQIDAQAB 
    -----END PUBLIC KEY----- 
""" 

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader) 
print(yaml.dump(data, Dumper=yaml.RoundTripDumper, indent=4)) 

ti dà:

pubkey: | 
    -----BEGIN PUBLIC KEY----- 
    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 
    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 
    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 
    EsUgJHXcpw7OPxRrCQIDAQAB 
    -----END PUBLIC KEY----- 

almeno con Python 2.7 e 3.5.

Il indent=4 è necessaria in quanto le RoundTripDumper default due spazi rientro e il rientro originale di un file non viene mantenuto (non farlo facilita ri-indentazione un file YAML).

Se non è possibile passare a ruamel.yaml si dovrebbe essere in grado di utilizzare la sua fonte per estrarre tutte le modifiche necessarie, ma se è possibile è possibile utilizzare anche le sue altre funzionalità come il commento e unire la conservazione del nome della chiave.

+0

Ben fatto. Stavo guardando attraverso la fonte pyyaml ​​cercando di capire dove si aggiungeva il nuovo extraline, quindi avrei potuto sperare di creare una sottoclasse, ma senza fortuna prima di andare a letto. – MattDMo

+0

@MattDMo La riga aggiuntiva nel dumper "normale" è perché la stringa contiene newlines. Esistono diversi modi per rappresentare stringhe con caratteri speciali e selezioni PyYAML questo. La selezione si trova in 'emitter.choose_scaler_style()' in base all'analisi dello scalare, ma il suo effettivo funzionamento è davvero difficile da rintracciare. Evito tutto ciò facendo un tipo speciale durante la lettura e impostando esplicitamente il suo stile nodo durante il dumping. – Anthon

+0

Ho appena installato 'ruamel.yaml' e ci ho giocato un po ': molto bello. Due domande rapide (fuori tema): da dove viene il nome e hai intenzione di supportare YAML 1.2? Chiedo perché ho alcuni file con cui mi piacerebbe lavorare che hanno come prima riga '% YAML 1.2'. Non ho idea di quali siano le differenze tra le specifiche (anche dopo aver letto la prima parte della specifica 1.2), o anche se i file sfruttano qualsiasi nuova funzionalità in 1.2 - sono principalmente chiavi di testo con valori stringa o booleani (nessun oggetto). Eccone uno su github: http://bit.ly/1JXLVbf – MattDMo