2016-05-17 8 views
1

小さなCLIユーティリティでTinyDBを使用して個人用の下書きを管理しています。データベースには、各ドラフトのメタデータが格納されます。ファイルを人間が編集できるようにする必要があります(手動で詳細を追加できるようにするため)、この理由から、JSONをフォーマットとしてYAMLを使用したいと思います。TinyDBでYAMLストレージを使用すると予期しない動作が発生する

TinyDBドキュメントに示されているように、私はYamlStorageクラスのサブクラスstorages.Storageを実装:insert_multipleを使用して、同時に一つだけの要素または複数の要素を挿入するとき

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 

すべてが正常に動作:

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) 

結果はdb.yaml

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

insertで要素を複数回挿入するときしかし、得られたYAMLファイルが異なる:

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} 

この形式のデータは、(離れメシエを見てから)であると思われますyaml.safe_loaddb.all()を呼び出すと[]と返されます)と互換性がありません。私の解釈は、YAMLのシリアル化プロセスは何らかの形で「あまりにも熱心」である、つまりElementインスタンスが基礎データの代わりにdb.yamlに書き込まれるということです。

私のコードに何か問題がありますか?私は別のYAMLモジュール(ruamel.yaml)を使ってPyYAMLオプションを試してみました。そして、違いなく、デフォルトのJSONStorageから2番目のYamlStorageクラスを作成しました。

バージョン情報:Python 3.4.3、TinyDB 3.2.0、PyYAML 3.11。私は、すべての輸入品と実行可能なMWEを投稿したhere

編集

@ Anthonのの提案の後、私はすぐにファイルにダンプする前にsys.stdoutにYAML出力を印刷してみました。この場合も問題が再現されます。 notebookを参照してください。

答えて

0

既存の「データベース」を更新すると、(2番目のYAMLファイルに表示されるように)状態情報を含むdatabase.Elementを取得します。

それは再びあなたがdictを保存していない保存されているが、dictのそのruamel.yaml(とPyYAMLと)のためのサブクラスであるこのElementのインスタンスがdictためdictitems(キーと値のペアの両方を保存する必要があります)とstate(その属性とその値を表す辞書)です。

書き込む前に、明示的dictにあなたの要素を変換すると、トリックを行う必要があります。

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

私はあなたの提案を試みたが、残念ながら違いを確認していないようです。関連性がある場合、 'yaml.dump'を呼び出す前の' print(type(data)) 'は' 'を返します。 – fndari

+0

私はむしろ 'stream = sys.stdout'でYAMLのダンプを行いたいので、YAMLが何を得ていると思うかを知ることができます。 – Anthon

+0

私は質問にノートブックへのリンクを 'sys.stdout'へのダンプとともに追加しました。 – fndari

関連する問題