python 3: десериализация вложенных словарей из sqlite - PullRequest
2 голосов
/ 03 апреля 2020

У меня есть функция sqlite3.register_converter:

def str_to_dict(s: ByteString) -> Dict:
    if s and isinstance(s, ByteString):
        s = s.decode('UTF-8').replace("'", '"')
        return json.loads(s)
    raise TypeError(f'value : "{s}" should be a byte string')

, которая возвращает текст этого исключения:

File "/usr/lib64/python3.7/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 30 (char 29)

при встрече с этой строкой:

s = b"{'foo': {'bar': [('for', 'grid')]}}"

Кажется, что проблема возникает из вложенного списка / кортежа / словаря, но я не понимаю, что в оболочке sqlite значение правильно возвращается командой select:

select * from table;

, тогда как то же самое Команда, выданная из сценария python, вернула исключение, указанное выше:

class SqliteDb:

    def __init__(self, file_path: str = '/tmp/database.db'):

        self.file_path = file_path
        self._db = sqlite3.connect(self.file_path, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES)
        if self._db:
            self._cursor = self._db.cursor()
        else:
            raise ValueError

        # register data types converters and adapters
        sqlite3.register_adapter(Dict, dict_to_str)
        sqlite3.register_converter('Dict', str_to_dict)

        sqlite3.register_adapter(List, list_to_str)
        sqlite3.register_converter('List', str_to_list)

    def __del__(self):
        self._cursor.close()
        self._db.close()

    def select_from(self, table_name: str):
        with self._db:
            query = f'SELECT * FROM {table_name}'
            self._cursor.execute(query)

if __name__ == '__main__':

    try:
        sq = SqliteDb()
        selection_item = sq.select_from("table")[0]
        print(f'selection_item : {selection_item}')

    except KeyboardInterrupt:
        print('\n')
        sys.exit(0)

s, значение уже сохранено в базе данных без проблем. Только выбор вызывает эту проблему. Итак, кто-нибудь знает, почему?

1 Ответ

2 голосов
/ 03 апреля 2020

Ваш ввод действительно является буквенным Python dict-литералом и содержит такие структуры, как кортеж ('for', 'grid'), которые не могут быть непосредственно проанализированы как JSON даже после замены одинарных кавычек на двойные кавычки.

Вы вместо этого можно использовать ast.literal_eval для анализа ввода:

from ast import literal_eval

def str_to_dict(s: ByteString) -> Dict:
    return literal_eval(s.decode())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...