2016-05-17 9 views
1

Ich verwende TinyDB für ein kleines CLI-Dienstprogramm, um persönliche Dokumententwürfe zu verwalten. Die Datenbank speichert Metadaten für jeden Entwurf; Die Datei sollte manuell editierbar sein (damit ich manuell Details hinzufügen kann), und aus diesem Grund möchte ich YAML über JSON als Format verwenden.Unerwartetes Verhalten bei Verwendung von YAML Storage mit TinyDB

ich implementiert eine YamlStorage Klasse Subklassifizieren storages.Storage wie in den TinyDB docs angegeben:

class TestYamlStorage(Storage): 
    """ 
    Store the data in a YAML file. 
    Written following the example at http://tinydb.readthedocs.io/en/latest/extend.html#write-a-custom-storage 
    """ 
    def __init__(self, filename): # (1) 
     super().__init__() 
     self.filename = filename 
     touch(filename) 

    def read(self): 
     with open(self.filename) as handle: 
      try: 
       data = yaml.load(handle.read()) 
       return data 
      except yaml.YAMLError: 
       return None # (3) 

    def write(self, data): 
     print('writing data: {}'.format(data)) 
     with open(self.filename, 'w') as handle: 
       yaml.dump(data, handle) 


    def close(self): # (4) 
     pass 

Alles funktioniert gut, wenn nur ein Element eingesetzt wird, oder mehrere Elemente gleichzeitig insert_multiple mit:

db = TinyDB('db.yaml', storage=TestYamlStorage) 
dicts = [ 
    dict(name='Homer', age=38), 
    dict(name='Marge', age=34), 
    dict(name='Bart', age=10) 
] 

# this works as expected 
db.insert_multiple(dicts) 

Die resultierende db.yaml:

_default: 
    1: {age: 38, name: Homer} 
    2: {age: 34, name: Marge} 
    3: {age: 10, name: Bart} 

Wenn jedoch Elemente mehrere Male mit insert Einsetzen ist die resultierende YAML-Datei anders:

db = TinyDB('db.yaml', storage=TestYamlStorage) 

db.insert(dict(name='Homer', age=38)) 
db.insert(dict(name='Bart', age=10)) 

db.yaml:

_default: 
    1: !!python/object/new:tinydb.database.Element 
    dictitems: {age: 38, name: Homer} 
    state: {eid: 1} 
    2: {age: 10, name: Bart} 

Die Daten in diesem Format (abgesehen von der Suche messier) scheint zu sein, nicht kompatibel mit yaml.safe_load (Aufruf db.all() gibt [] zurück). Meine Interpretation ist, dass der YAML-Serialisierungsprozess in gewisser Weise "übereifrig" ist, d. H. Dass die Element -Instanz anstelle der zugrunde liegenden Daten in db.yaml geschrieben wird.

Ist mit meinem Code etwas nicht in Ordnung? Ich habe versucht, mit PyYAML-Optionen zu experimentieren, ein anderes YAML-Modul (ruamel.yaml) zu verwenden und eine zweite YamlStorage-Klasse zu erstellen, die von der Standard-JSONStorage kopiert, aber ohne Unterschied.

Versionsinfo: Python 3.4.3, TinyDB 3.2.0, PyYAML 3.11. Ich habe ein lauffähiges MWE mit allen Importen here gepostet.

bearbeiten

Nach @ Anthon Vorschlag, ich sys.stdout sofort den YAML Ausgangsdruck versucht, bevor eine Datei Dumping. Das Problem wird auch in diesem Fall reproduziert. Siehe notebook.

Antwort

0

Wenn Sie eine vorhandene "Datenbank" aktualisieren, erhalten Sie eine database.Element, die (wie Sie in der zweiten YAML-Datei sehen) Statusinformationen enthält.

Wenn wieder, dass gespeichert wird Sie keine dict, sondern eine Instanz dieser Element speichern, die eine Unterklasse von dict ist und dass ruamel.yaml (und PyYAML) sowohl die dictitems (die Schlüssel-Wert-Paare für die dict speichern muss) und state (ein Wörterbuch, das diese Attribute und ihre Werte darstellt).

Konvertieren Ihr Element zu einem dict ausdrücklich vor dem Schreiben sollte es tun:

def write(self, data): 
     print('writing data: {}'.format(data)) 
     with open(self.filename, 'w') as handle: 
       yaml.dump(dict(data), handle) 
    #      ^^^^ ^
+0

ich Ihren Vorschlag versucht, aber leider scheint es nicht einen Unterschied zu machen. Wenn es relevant sein kann, gibt 'print (type (data))' zurück, bevor der Aufruf von 'yaml.dump'' 'zurückgibt. – fndari

+0

Ich würde lieber einen YAML-Dump mit 'stream = sys.stdout' machen, damit Sie sehen können, was YAML denkt. – Anthon

+0

Ich habe einen Link zu einem Notebook zu meiner Frage mit dem Dump zu 'sys.stdout' hinzugefügt. – fndari

Verwandte Themen