2012-11-22 15 views
13

Sto creando documenti Yaml dai miei oggetti Python utilizzando PyYaml. per esempio il mio oggetto: Aggiunta di commenti a YAML prodotto con PyYaml

class MyObj(object): 
    name = "boby" 
    age = 34 

diventa:

boby: 
    age: 34 

Fin qui tutto bene.

Ma non ho trovato un modo per aggiungere a livello di codice commenti al yaml prodotta in modo che sarà del tipo:

boby:  # this is the name 
    age: 34 # in years 

Guardando la documentazione PyYaml e anche al codice, ho trovato alcun modo di farlo.

Qualche suggerimento?

+0

Sono quasi certo che non c'è modo di farlo con PyYAML, in pratica, essenzialmente per riscrivere le parti principali della libreria e prendere una serie di decisioni su come gestire i commenti. Volete i commenti aggiunti dal rappresentante (ad esempio, per classe)? O per esempio in qualche modo (anche più difficile)? Questo è un po 'sfortunato, in quanto la possibilità di aggiungere commenti potrebbe essere in qualche modo utile. – cge

+0

Grazie a @cge. Conservare i commenti sarebbe molto utile quando si elaborano i documenti yaml in modo programmatico. –

+0

http://www.dzone.com/snippets/pyyaml-comment-emitter sembra capire come farlo usando le interfacce Event/Dumper. Non pubblicare ancora una risposta perché non ho ancora verificato che funzioni. – kampu

risposta

4

Probabilmente avete qualche representer per la classe MyObj, come di default dumping (print(yaml.dump(MyObj()))) con PyYAML vi darà:

!!python/object:__main__.MyObj {} 

PyYAML può fare solo una cosa con i commenti in l'output desiderato: disfarsene . Se volete leggere che l'output desiderato indietro, si finisce con un dict contenente un dict ({'boby': {'age': 34}}, non si ottiene un'istanza MyObj() perché non ci sono informazioni tag)

La versione avanzata per PyYAML che ho sviluppato (ruamel.yaml) può leggere in YAML con commenti, conservare i commenti e scrivere commenti durante il dumping. Se si legge l'output desiderato, i dati risultanti appariranno (e agiranno) come un dict contenente un dict, ma in realtà esiste una struttura dati più complessa in grado di gestire i commenti. Tuttavia è possibile creare tale struttura quando ruamel.yaml chiede di scaricare un'istanza di MyObj e se si aggiungono i commenti in quel momento, si otterrà l'output desiderato.

from __future__ import print_function 

import sys 
import ruamel.yaml 
from ruamel.yaml.comments import CommentedMap 


class MyObj(): 
    name = "boby" 
    age = 34 

    def convert_to_yaml_struct(self): 
     x = CommentedMap() 
     a = CommentedMap() 
     x[data.name] = a 
     x.yaml_add_eol_comment('this is the name', 'boby', 11) 
     a['age'] = data.age 
     a.yaml_add_eol_comment('in years', 'age', 11) 
     return x 

    @staticmethod 
    def yaml_representer(dumper, data, flow_style=False): 
     assert isinstance(dumper, ruamel.yaml.RoundTripDumper) 
     return dumper.represent_dict(data.convert_to_yaml_struct()) 


ruamel.yaml.RoundTripDumper.add_representer(MyObj, MyObj.yaml_representer) 

ruamel.yaml.round_trip_dump(MyObj(), sys.stdout) 

che stampa:

boby:  # this is the name 
    age: 34 # in years 

Non v'è alcuna necessità di attendere con la creazione delle CommentedMap casi fino a quando si vuole rappresentare l'istanza MyObj. Vorrei ad es. make name e age in proprietà che ottengono/impongono valori da/sull'appropriato CommentedMap. In questo modo è possibile aggiungere più facilmente i commenti prima che il metodo statico yaml_representer venga chiamato per rappresentare l'istanza MyObj.