Why does structuring of datetime in attrs class need a structure hook?
kkg-else42 opened this issue · 1 comments
- cattrs version: 23.2.3
- Python version: 3.11
- Operating System: Windows (dev)/Linux (prod
Hey there!
In the following situation it is necessary to use a structure hook for the handling of datetime. And I know how to do that.
But I would be interested to know why it is necessary.
import attrs
import cattrs
import datetime
@attrs.frozen
class A:
dt: datetime.datetime
print(cattrs.structure({'dt': datetime.datetime(2024, 3, 26, 16, 40, 30)}, A))
So this is how it works. Cattrs binds types to functions (hooks). The defaults are different when structuring and unstructuring because data is treated differently when entering and exiting your system.
Every type needs a hook. If a hook does not exist, the fallback hook factory gets called, and by default that will cause an exception to be raised.
You may be wondering why the fallback hook doesn't do an isinstance
check before raising, and the answer is that there are a lot of edge cases where that wouldn't work (especially with fancy types, protocols, newtypes, type aliases...), and a whitelist approach is easier to understand.
That said, you can assume responsibility for this yourself like this:
def structure_hook_factory(type):
def hook(val, _):
if not isinstance(val, type):
raise ValueError("Wrong type")
return val
return hook
c = Converter(structure_fallback_factory=structure_hook_factory)
print(c.structure({"dt": datetime.datetime(2024, 3, 26, 16, 40, 30)}, A))
>>> A(dt=datetime.datetime(2024, 3, 26, 16, 40, 30))
So it's a design choice!