marshmallow
marshmallow copied to clipboard
dumping a dictionary with a schema containing an optional field 'items'
I'll start with a simple example
from dataclasses import dataclass
from marshmallow import Schema, fields
class ListItem(Schema):
foo = fields.Str(required=True)
class MySchema(Schema):
bar = fields.Str(required=True)
items = fields.List(fields.Nested(ListItem()), required=True)
@dataclass
class Thing:
bar: str = None
thing = Thing(bar="barbarbar")
d = {"bar": "barbarbar"}
print(MySchema().dump(obj=thing)) # this works
print(MySchema().dump(obj=d)) # this gives an error "TypeError: 'builtin_function_or_method' object is not iterable"
The issue appears because on utils.py
's function _get_value_for_key
it first tries to getattr, then obj[key] (without default), and finally getattr again, resulting in the items
method for dict, rather than a default. This is extremely unexpected behaviour.
A workaround is to override get_attribute
to try .get
first on dictionaries.
class MyBaseSchema(Schema):
def get_attribute(self, obj: Any, attr: str, default: Any):
"""Defines how to pull values from an object to serialize."""
if isinstance(obj, Dict):
return obj.get(attr, default)
return getattr(obj, attr, default)
I am not sure what the prefered fix in marshmallow would be given the rather dizzying levels of indirection and cases in the get attribute chain.
Hello,
I hit exactly the same issue with marshmallow 3.12.1 but with values
instead of items
(and I didn't try, but I think that the problem is there with any other builtin method, like keys
)
Edit: It seems to me that the problem only occurs only if the values/items key is missing in the dictionary... Only in that case the serialization is falling back to the extraction of the builtin method