Я использую TinyDB для небольшой утилиты CLI для управления чертежами личного документа. База данных хранит метаданные для каждого проекта; файл должен быть правдоподобным (чтобы я мог вручную добавлять данные), и по этой причине я хотел бы использовать YAML над JSON в качестве формата.Неожиданное поведение при использовании хранилища YAML с TinyDB
Я реализовал YamlStorage
класса подклассов storages.Storage
, как указано в TinyDB документы:
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
вместо базовых данных.
С кодом нет в коде? Я попытался поиграть с параметрами PyYAML, используя другой модуль YAML (ruamel.yaml) и создать второй класс классов YamlStorage из JSONStorage по умолчанию, но без какой-либо разницы.
Информация о версии: Python 3.4.3, TinyDB 3.2.0, PyYAML 3.11. Я опубликовал runwable MWE со всеми импортными данными here.
Редактировать
После @ предложение ANTHON, я попробовал напечатать вывод YAML в sys.stdout
сразу перед сбросом в файл. В этом случае проблема воспроизводится. См. notebook.
Я попробовал ваше предложение, но, к сожалению, не похоже, чтобы сделать разницу. Если это может быть актуально, 'print (type (data))' перед вызовом 'yaml.dump' возвращает' '. –
fndari
Я предпочел бы сделать дамп YAML с 'stream = sys.stdout', чтобы вы могли видеть, что YAML думает, что он получает. – Anthon
Я добавил ссылку на блокнот на мой вопрос с дампом 'sys.stdout'. – fndari