You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
importattrsimportcattrs@attrs.defineclassA:
x: list[str] =attrs.field(
converter=attrs.converters.default_if_none(factory=list),
factory=list,
)
print(A())
print(A(x=None))
a=cattrs.structure({}, A)
print(a)
a=cattrs.structure({"x": None}, A)
print(a)
Output:
A(x=[])
A(x=[])
A(x=[])
+ Exception Group Traceback (most recent call last):
| File "/home/dbn/src/rockfish/cuttlefish/bar.py", line 21, in <module>
| a = cattrs.structure({"x": None}, A)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/dbn/usr/py-3.11/lib/python3.11/site-packages/cattrs/converters.py", line 332, in structure
| return self._structure_func.dispatch(cl)(obj, cl)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "<cattrs generated structure __main__.A>", line 10, in structure_A
| cattrs.errors.ClassValidationError: While structuring A (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "<cattrs generated structure __main__.A>", line 6, in structure_A
| File "/home/dbn/usr/py-3.11/lib/python3.11/site-packages/cattrs/converters.py", line 519, in _structure_list
| for e in obj:
| TypeError: 'NoneType' object is not iterable
| Structuring class A @ attribute x
+------------------------------------
My desired output would be 4 lines of A(x=[]), no exception.
The text was updated successfully, but these errors were encountered:
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:
importattrsimportcattrs@attrs.defineclassA:
x: list[str] =attrs.Factory(list)
c=cattrs.Converter()
defnone_aware_list_hook(val, type):
"""A structure hook that can also handle None."""ifvalisNone:
return []
returnc.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 ;)
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.The text was updated successfully, but these errors were encountered: