2012-11-08 10 views
6

Ho un file ambiente YAML che crea alcuni record nel db:PyYAML: Controllo ordine delle voci chiamati da yaml.load()

setting1: 
    name: [item,item] 
    name1: text 
anothersetting2: 
    name: [item,item] 
    sub_setting: 
     name :[item,item] 

quando aggiorno questo file con Setting3 e rigenerare record nel db da:

import yaml 
fh = open('setting.txt', 'r') 
setting_list = yaml.load(fh) 
for i in setting_list: 
    add_to_db[i] 

è di vitale importanza che l'ordine di loro impostazioni (numeri ID in dB) rimanere lo stesso ogni volta come im li addig al db ... e Setting3 ottiene appena aggiunto alla yaml.load() La fine è tale che il suo id non confonde nessun record che sia già io n il db ... Al momento ogni volta aggiungo un'altra impostazione e chiamo i record yaml.load() che vengono caricati in ordine diverso, il che si traduce in diversi ID. Gradirei tutte le idee;)

EDIT: Ho seguito abarnert suggerimenti e preso questa sostanza https://gist.github.com/844388

funziona come previsto, grazie!

+0

Primo, è questo 'PyYAML', o qualcos'altro? Non esiste un modulo 'yaml' incorporato e almeno due pacchetti PyPI che forniscono un modulo' yaml'. In generale, ogni volta che utilizzi un modulo di terze parti, dovresti dire da dove lo hai preso. – abarnert

+0

Qualunque modulo tu stia usando, devi agganciare il modo in cui converte i nodi di mappatura in Python, quindi usa un 'collection.OrderedDict' invece di un' dict'. Con altri moduli oltre a PyYAML, non ne ho idea. Con 'PyYAML', questo è sicuramente possibile, ma complicato se ti stai attenendo ai metodi di convenienza di alto livello. Altrove, qualcuno ha menzionato che è stato più facile da monkeypatch piuttosto che usare i ganci previsti. – abarnert

+0

Sto usando PyYAML come suggerirebbe il titolo di questa domanda ... -> PyYAML: Controlla l'ordine degli oggetti chiamati da yaml.load(). Grazie per il tuo consiglio!! – zzart

risposta

4

Le specifiche YAML indicano chiaramente che l'ordine delle chiavi all'interno di una mappatura è un "dettaglio di rappresentazione" a cui non si può fare affidamento. Quindi il tuo file delle impostazioni è già non valido se si basa sul mapping e starai molto meglio usando YAML valido, se possibile.

Ovviamente YAML è estensibile e non c'è nulla che ti impedisca di aggiungere un tipo di "mapping ordinato" ai tuoi file di impostazioni. Per esempio:

!omap setting1: 
    name: [item,item] 
    name1: text 
!omap anothersetting2: 
    name: [item,item] 
    !omap sub_setting: 
     name :[item,item] 

Lei non ha citato quale modulo yaml si sta utilizzando. Non esiste un tale modulo nella libreria standard e ci sono almeno due pacchetti solo su PyPI che forniscono moduli con quel nome. Comunque, ho intenzione di indovinare che è PyYAML, perché per quanto ne so è il più popolare.

L'estensione sopra descritta è facile da analizzare con PyYAML. Vedi http://pyyaml.org/ticket/29:

def omap_constructor(loader, node): 
    return loader.construct_pairs(node) 
yaml.add_constructor(u'!omap', omap_constructor) 

Ora, invece di:

{'anothersetting2': {'name': ['item', 'item'], 
    'sub_setting': 'name :[item,item]'}, 
'setting1': {'name': ['item', 'item'], 'name1': 'text'}} 

Otterrete questo:

(('anothersetting2', (('name', ['item', 'item']), 
    ('sub_setting', ('name, [item,item]'),))), 
('setting1', (('name', ['item', 'item']), ('name1', 'text')))) 

Naturalmente questo ti dà una tuple di chiave-valore tuple s, ma puoi facilmente scrivere un construct_ordereddict e ottenere invece un OrderedDict. È anche possibile scrivere un rappresentatore che memorizza oggetti OrdereredDict come !omap s, se è necessario produrre anche l'input.

Se davvero si vuole agganciare PyYAML per renderlo utilizzare un OrderedDict invece di un dict per mappature di default, è abbastanza facile da fare se si sta già lavorando direttamente sugli oggetti parser, ma più difficile se si vuole attaccare con i metodi di convenienza di alto livello. Fortunatamente, il ticket sopraindicato ha un'implementazione che puoi usare.Ricorda che non stai più utilizzando la vera YAML, ma una variante, quindi qualsiasi altro software che si occupa dei tuoi file può, e probabilmente lo farà, rompere.

0

Ultimo ho sentito, PyYAML non ha supportato questo, anche se sarebbe probabilmente facile modificarlo per accettare un dizionario o un oggetto simile a un dizionario come punto di partenza.

+0

Questo non funzionerebbe davvero. Innanzitutto, i documenti YAML non devono essere dizionari. In secondo luogo, se inizi con, ad esempio, un 'OrderedDict', tutti i sottodiretti saranno ancora 'dict'. Quindi quello di cui hai veramente bisogno è di modificarlo per accettare un costruttore diverso da usare al posto di 'dict' (e, idealmente, uno per ogni costruttore che usa, anche se gli altri non saranno utili come spesso). – abarnert

3

Ora è possibile utilizzare ruaml.yaml per questo.

Da https://pypi.python.org/pypi/ruamel.yaml:

ruamel.yaml è un parser YAML/emettitore che supporta andata e ritorno conservazione dei commenti, stile ss/mappa di flusso, e mappare ordine chiave

0

per una data singola elemento che è noto per essere un dizionario ordinato basta creare gli elementi di un elenco e utilizzare le raccolte.OrderedDict:

setting1: 
    - name: [item,item] 
    - name1: text 
anothersetting2: 
    - name: [item,item] 
    - sub_setting: 
     name :[item,item] 

import collections 
import yaml 
fh = open('setting.txt', 'r') 
setting_list = yaml.load(fh) 

setting1 = collections.OrderedDict(list(x.items())[0] for x in setting_list['setting1'])