Package: marshmallow-dataclass
marshmallow-dataclassAutomatic generation ofmarshmallowschemas from dataclasses.fromdataclassesimportdataclass,fieldfromtypingimportList,Optionalimportmarshmallow_dataclassimportmarshmallow.validate@dataclassclassBuilding:# field metadata is used to instantiate the marshmallow fieldheight:float=field(metadata={"validate":marshmallow.validate.Range(min=0)})name:str=field(default="anonymous")@dataclassclassCity:name:Optional[str]buildings:List[Building]=field(default_factory=list)city_schema=marshmallow_dataclass.class_schema(City)()city=city_schema.load({"name":"Paris","buildings":[{"name":"Eiffel Tower","height":324}]})# => City(name='Paris', buildings=[Building(height=324.0, name='Eiffel Tower')])city_dict=city_schema.dump(city)# => {'name': 'Paris', 'buildings': [{'name': 'Eiffel Tower', 'height': 324.0}]}WhyUsing schemas in Python often means having both a class to represent your data and a class to represent its schema, which results in duplicated code that could fall out of sync.
As of Python 3.6, types can be defined for class members, which allows libraries to generate schemas automatically.Therefore, you can document your APIs in a way that allows you to statically check that the code matches the documentation.InstallationThis packageis hosted on PyPI.pip3installmarshmallow-dataclassYou may optionally install the following extras:enum: enum support for marshmallow versions <3.18marshmallow-enum.union: for translating pythonUniontypesto union fields.pip3install"marshmallow-dataclass[enum,union]"marshmallow 2 supportmarshmallow-dataclassno longer supports marshmallow 2.
Installmarshmallow_dataclass<6.0if you need marshmallow 2 compatibility.UsageUse theclass_schemafunction to generate a marshmallowSchemaclass from adataclass.fromdataclassesimportdataclassfromdatetimeimportdateimportmarshmallow_dataclass@dataclassclassPerson:name:strbirth:datePersonSchema=marshmallow_dataclass.class_schema(Person)The type of your fields must be either basictypes supported by marshmallow(such asfloat,str,bytes,datetime, ...),Union, or other dataclasses.Union (de)serialization coercionTypically the Union type;Union[X, Y]means—from a set theory perspective—eitherXorY, i.e., an unordered set, howevever the order of the sub-types defines the precedence when attempting to ether deserialize or serialize the value perhere.For example,fromtypingimportUnionfromdataclassesimportdataclass@dataclassclassPerson:name:strage:Union[int,float]PersonSchema=marshmallow_dataclass.class_schema(Person)PersonSchema().load({"name":"jane","age":50.0})# => Person(name="jane", age=50)will first (sucessfully) try to coerce50.0to anint. If coercion is not desired theAnytype can be used with the caveat that values will not be type checked without additionalvalidation.Customizing generated fieldsTo pass arguments to the generated marshmallow fields (e.g.,validate,load_only,dump_only, etc.),
pass them to themetadataargument of thefieldfunction.Note that starting with version 4, marshmallow will disallow passing arbitrary arguments, so any
additional metadata should itself be put in its ownmetadatadict:fromdataclassesimportdataclass,fieldimportmarshmallow_dataclassimportmarshmallow.validate@dataclassclassPerson:name:str=field(metadata=dict(load_only=True,metadata=dict(description="The person's first name")))height:float=field(metadata=dict(validate=marshmallow.validate.Range(min=0)))PersonSchema=marshmallow_dataclass.class_schema(Person)@dataclassshortcutmarshmallow_dataclassprovides a@dataclassdecorator that behaves like the standard library's@dataclasses.dataclassand adds aSchemaattribute with the generated marshmallowSchema.# Use marshmallow_dataclass's @dataclass shortcutfrommarshmallow_dataclassimportdataclass@dataclassclassPoint:x:floaty:floatPoint.Schema().dump(Point(4,2))# => {'x': 4, 'y': 2}Note: Since the.Schemaproperty is added dynamically, it can confuse type checkers.
To avoid that, you can declareSchemaas aClassVar.fromtypingimportClassVar,Typefrommarshmallow_dataclassimportdataclassfrommarshmallowimportSchema@dataclassclassPoint:x:floaty:floatSchema:ClassVar[Type[Schema]]=SchemaCustomizing the base SchemaIt is also possible to derive all schemas from your own
base Schema class
(seemarshmallow's documentation about extendingSchema).
This allows you to implement custom (de)serialization
behavior, for instance specifying a custom mapping between your classes and marshmallow fields,
or renaming fields on serialization.Custom mapping between classes and fieldsclassBaseSchema(marshmallow.Schema):TYPE_MAPPING={CustomType:CustomField,List:CustomListField}classSample:my_custom:CustomTypemy_custom_list:List[int]SampleSchema=marshmallow_dataclass.class_schema(Sample,base_schema=BaseSchema)# SampleSchema now serializes my_custom using the CustomField marshmallow field# and serializes my_custom_list using the CustomListField marshmallow fieldRenaming fields on serializationimportmarshmallowimportmarshmallow_dataclassclassUppercaseSchema(marshmallow.Schema):"""A Schema that marshals data with uppercased keys."""defon_bind_field(self,field_name,field_obj):field_obj.data_key=(field_obj.data_keyorfield_name).upper()classSample:my_text:strmy_int:intSampleSchema=marshmallow_dataclass.class_schema(Sample,base_schema=UppercaseSchema)SampleSchema().dump(Sample(my_text="warm words",my_int=1))# -> {"MY_TEXT": "warm words", "MY_INT": 1}You can also passbase_schematomarshmallow_dataclass.dataclass.@marshmallow_dataclass.dataclass(base_schema=UppercaseSchema)classSample:my_text:strmy_int:intSeemarshmallow's documentation about extendingSchema.Custom NewType declarationsThis library exports aNewTypefunction to create types that generatecustomized marshmallow fields.Keyword arguments toNewTypeare passed to the marshmallow field constructor.importmarshmallow.validatefrommarshmallow_dataclassimportNewTypeIPv4=NewType("IPv4",str,validate=marshmallow.validate.Regexp(r"^([0-9]{1,3}\\.){3}[0-9]{1,3}$"))You can also pass a marshmallow field toNewType.importmarshmallowfrommarshmallow_dataclassimportNewTypeEmail=NewType("Email",str,field=marshmallow.fields.Email)For convenience, some custom types are provided:frommarshmallow_dataclass.typingimportEmail,UrlNote: if you are usingmypy, you will notice thatmypythrows an error if a variable defined withNewTypeis used in a type annotation. To resolve this, add themarshmallow_dataclass.mypyplugin
to yourmypyconfiguration, e.g.:[mypy]plugins=marshmallow_dataclass.mypy# ...MetaoptionsMetaoptionsare set the same way as a marshmallowSchema.frommarshmallow_dataclassimportdataclass@dataclassclassPoint:x:floaty:floatclassMeta:ordered=TrueDocumentationThe project documentation is hosted on GitHub Pages:https://lovasoa.github.io/marshmallow_dataclass/ContributingTo install this project and make changes to it locally, follow the instructions inCONTRIBUTING.md.