1

我正在使用 TinyDB 作为一个小型 CLI 实用程序来管理个人文档草稿。数据库存储每个草稿的元数据;该文件应该是人工可编辑的(以便我可以手动添加详细信息),因此我想使用 YAML over JSON 作为格式。

我实现了TinyDB 文档中所示的YamlStorage类子类化:storages.Storage

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

使用以下方法仅插入一个元素或同时插入多个元素时一切正常insert_multiple

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_load(调用db.all()返回[])不兼容。我的解释是 YAML 序列化过程在某种程度上“过于急切”,即Element实例被写入db.yaml而不是底层数据。

我的代码有问题吗?我尝试使用不同的 YAML 模块 (ruamel.yaml) 来摆弄 PyYAML 选项,并从默认 JSONStorage 复制创建第二个 YamlStorage 类,但没有任何区别。

版本信息:Python 3.4.3、TinyDB 3.2.0、PyYAML 3.11。我在这里发布了一个包含所有导入的可运行 MWE 。

编辑

在@Anthon 的建议之后,我尝试sys.stdout在转储到文件之前立即打印 YAML 输出。在这种情况下也重现了该问题。见笔记本

4

1 回答 1

0

当您更新现有的“数据库”时,您会检索一个database.Element包含(如您在第二个 YAML 文件中看到的)状态信息的信息。

当再次保存时,您不会保存 a dict,而是 this 的一个实例,Element它是dictand的子类ruamel.yaml(和 PyYAML)需要存储dictitems(的键值对dict)和state(表示该属性的字典和他们的价值观)。

在编写之前将您的元素dict显式转换为 a 应该可以解决问题:

    def write(self, data):
        print('writing data: {}'.format(data))
        with open(self.filename, 'w') as handle:
                yaml.dump(dict(data), handle)
    #                      ^^^^    ^
于 2016-05-17T16:10:41.680 回答