python - 使用 cattrs 解构复杂的类

标签 python json datetime python-attrs

我在使用 attrs/cattrs 将自定义数据类转换为 JSON 格式时遇到问题。我的类(class)具有以下形式:

import attr
from datetime import datetime
from typing import Tuple, Set, Dict, FrozenSet

@attr.s(auto_attribs=True)
class B:
    w: Set[datetime] = attr.ib()
    x: Set[str] = attr.ib()
    y: Set['A'] = attr.ib()
    z: Set[Tuple[datetime, str]] = attr.ib(factory=set)


@attr.s(auto_attribs=True, cmp=False)
class A:
    a: str = attr.ib()
    b: FrozenSet[Team] = attr.ib()
    c: FrozenSet[Tuple[datetime, str]] = attr.ib(factory=frozenset)
    d: Dict[Tuple[str, str], float] = attr.ib(factory=dict)

我面临的问题是,当我尝试通过 cattrs.unstruct 转换为 dict 时,反之亦然通过 cattrs.struct , cattrs 显示一个错误,告诉我应该使用钩子(Hook):

import cattr

# Create instance of b
b_instance = B(...)
...
data = cattr.unstructure(b_instance)
print()
print(data)
print()
restored = cattr.structure(data, B)
assert b_instance == restored
ValueError: Unsupported type: <class 'datetime.datetime'>. Register a structure hook for it.

我注册了一个钩子(Hook),以将datetime转换为给定格式的str:

import cattr
from datetime import datetime

time_format = '%Y-%m-%d %H:%M:%S'
cattr.register_unstructure_hook(datetime, lambda dt: dt.strftime(time_format))
cattr.register_structure_hook(datetime, lambda s, _: datetime.strptime(s, time_format))

但是我收到以下错误:

TypeError: strptime() argument 1 must be str, not datetime.datetime

我需要能够使用 %Y-%m-%d %H:%M:%S 格式的日期时间在对象实例和 JSON 之间进行转换。我怎样才能实现这一目标?

最佳答案

问题出在 Set 类型上。如果它存在于类型中,则 cattr.unstruct 无法序列化它。将其替换为元组,事情就会解决:

from typing import Tuple, Set
from datetime import datetime

import cattr
import attr
import pytest


TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
COMPLEX_TYPE = Tuple[Tuple[str, datetime]]
COMPLEX_TYPE_BAD = Set[Tuple[str, datetime]]

cattr.register_unstructure_hook(
    datetime, lambda dt: datetime.strftime(dt, format=TIME_FORMAT)
)
cattr.register_structure_hook(
    datetime, lambda dt_str, _: datetime.strptime(dt_str, TIME_FORMAT)
)


def test_cattrs_io_for_a():
    @attr.s(auto_attribs=True)
    class A:
        ds: datetime = attr.ib(factory=datetime.utcnow)

    a = A()
    a_ser = cattr.unstructure(a)
    a_des = cattr.structure(a_ser, A)
    assert isinstance(a_des, A)


def test_cattrs_io_for_b():
    @attr.s(auto_attribs=True)
    class B:
        ds: COMPLEX_TYPE = attr.ib(factory=set)

    b = B((("a", datetime.utcnow()), ("b", datetime.utcnow())))
    b_ser = cattr.unstructure(b)
    b_des = cattr.structure(b_ser, B)
    assert isinstance(b_des, B)


def test_cattrs_io_for_b_bad():
    @attr.s(auto_attribs=True)
    class B:
        ds: COMPLEX_TYPE_BAD = attr.ib(factory=set)

    b = B({("a", datetime.utcnow()), ("b", datetime.utcnow())})
    b_ser = cattr.unstructure(b)
    with pytest.raises(TypeError):
        b_des = cattr.structure(b_ser, B)
        assert isinstance(b_des, B)

这看起来像是cattrs https://github.com/Tinche/cattrs/issues/48 中的一个问题

将在下一版本的 cattrs 中修复。或者您可以从 master 分支构建它

关于python - 使用 cattrs 解构复杂的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55127722/

相关文章:

python - 迭代字典列表时获取字典列表的索引

python - 在 Python 中执行 Ruby array.pack 的等效方法

javascript - js网格 : Adding a row using json data

python - 从深度嵌套的 JSON 创建 Pandas DataFrame

javascript - 如何在javascript中将提供的小时数转换为天数小时分钟?

python - tkinter 和 GUI 编程方法

python - 我是否需要锁定来保护我的代码中的多线程竞争条件

javascript - Angular 5 服务读取本地 .json 文件

ruby - ruby 中的时间操作

delphi - DateUtils 中的 IncHour 过程