Closed danielnelson closed 3 months ago
Hi,
I'm on paternity leave right now so my availability is limited ;)
Here's how I would approach this: instead of installing a converter on the class itself, I would customize how cattrs deals with the x
field when loading the data. I would do this my writing my custom hook, and registering it on the x
field. Here's the code:
import attrs
import cattrs
@attrs.define
class A:
x: list[str] = attrs.Factory(list)
c = cattrs.Converter()
def none_aware_list_hook(val, type):
"""A structure hook that can also handle None."""
if val is None:
return []
return c.structure(val, type)
c.register_structure_hook(
A,
cattrs.gen.make_dict_structure_fn(
A, c, x=cattrs.override(struct_hook=none_aware_list_hook)
),
)
print(A())
print(A(x=None))
a = c.structure({}, A)
print(a)
a = c.structure({"x": None}, A)
print(a)
This will print:
A(x=[])
A(x=None)
A(x=[])
A(x=[])
Personally I would be OK with this since it isolates the special case None
handling to cattrs - when dealing with the class directly, there's no special behavior. That's one of the benefits of using cattrs - weirdness can be isolated to exactly where it's needed ;)
This isn't the only way of handling cases like this, but it's what I'd use first. Let me know if you have any other questions, will close this now ;)
This is perfect, thank you.
Description
This is an issue I can workaround but I would like to know if there is a better way to do it.
I have a type that should have a field with a list type and I want it to default to an empty list. I'm converting from a JSON API that sets the field as null if it is not set and I want cattrs to use the default factory for the field if it is None.
I used
attrs.converters.default_if_none
, though I'm not particularly fond of it. If there is a way in the converter to make this go away I would prefer it.What I Did
Output:
My desired output would be 4 lines of
A(x=[])
, no exception.