marshmallow_dataclass
marshmallow_dataclass copied to clipboard
Is it possible to use this with the full set of marshmallow's supported fields?
Apologies is this is a dumb question, but I'm a bit confused about what field types are allowed or how to support them. For example, using just marshmallow I can set up a dataclass and schema like this:
@dataclass
class FourTupleFilter:
ip_src: Optional[IPv4Interface] = None
ip_dst: Optional[IPv4Interface] = None
port_src: Optional[int] = None
port_dst: Optional[int] = None
class FourTupleFilterSchema(Schema):
ip_src = fields.IPv4Interface()
ip_dst: fields.IPv4Interface()
port_src: fields.Int()
port_dst: fields.Int()
@post_load
def make_filter(self, data, **kwargs):
return FourTupleFilter(**data)
schema = FourTupleFilterSchema()
schema.loads('{"ip_src": "192.168.1.1"}')
# FourTupleFilter(ip_src=IPv4Interface('192.168.1.1/32'), ip_dst=None, port_src=None, port_dst=None)
as Ipv4Interface
is part of https://marshmallow.readthedocs.io/en/stable/marshmallow.fields.html?highlight=fields#module-marshmallow.fields
However, if I try to do the same thing with an automatically generated schema from marshmallow_dataclass trying to deserialize the same input results in ValidationError: {'ip_src': {'_schema': ['Invalid input type.']}}
Is there some config I'm missing or does this package only work with basic data types?
By default, marshmallow_dataclass
knows what field types to use for types which are listed in marshmallow.Schema.TYPE_MAPPING
. Marshmallow's TYPE_MAPPING
does not currently include IPv4Interface
— I'm not sure why.
The (or a) way around this is to use a custom Schema base class that augments TYPE_MAPPING
to include whatever types or customizations you need. (Here is the section on this in the README.)
This works:
from dataclasses import dataclass
from ipaddress import IPv4Interface
from typing import Optional
import marshmallow
import marshmallow_dataclass
class BaseSchema(marshmallow.Schema):
TYPE_MAPPING = {IPv4Interface: marshmallow.fields.IPv4Interface}
@dataclass
class FourTupleFilter:
ip_src: Optional[IPv4Interface] = None
ip_dst: Optional[IPv4Interface] = None
port_src: Optional[int] = None
port_dst: Optional[int] = None
schema_class = marshmallow_dataclass.class_schema(
FourTupleFilter, base_schema=BaseSchema
)
schema = schema_class()
print(schema.loads('{"ip_src": "192.168.1.1"}'))
For the sake of completeness in posterity, one may also specify a marshmallow.fields.Field
instance to use directly using dataclasses.field
by setting marshmallow_field
in the fields metadata
:
from dataclasses import dataclass
from dataclasses import field
from ipaddress import IPv4Interface
from typing import Optional
import marshmallow
import marshmallow_dataclass
@dataclass
class FourTupleFilter:
ip_src: Optional[IPv4Interface] = field(
default=None,
metadata={"marshmallow_field": marshmallow.fields.IPv4Interface()}
)
ip_dst: Optional[IPv4Interface] = field(
default=None,
metadata={"marshmallow_field": marshmallow.fields.IPv4Interface()}
)
port_src: Optional[int] = None
port_dst: Optional[int] = None
schema_class = marshmallow_dataclass.class_schema(FourTupleFilter)
schema = schema_class()
print(schema.loads('{"ip_src": "192.168.1.1"}'))
Closing, since this is a request for help rather than an issue report.