python 3:从sqlite反序列化嵌套字典

时间:2020-04-03 16:42:28

标签: json python-3.x sqlite nested

我有这个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 shell中,使用选择命令正确返回了值:

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 个答案:

答案 0 :(得分:2)

您的输入实际上是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())