- Notifications
You must be signed in to change notification settings - Fork76
Automatic generation of marshmallow schemas from dataclasses.
License
lovasoa/marshmallow_dataclass
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Automatic generation ofmarshmallow schemas 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}]}
Using 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.
This packageis hosted on PyPI.
pip3 install marshmallow-dataclass
pip3 install"marshmallow-dataclass"
marshmallow-dataclass
no longer supports marshmallow 2.Installmarshmallow_dataclass<6.0
if you need marshmallow 2 compatibility.
Use theclass_schema
function 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.
Typically the Union type;Union[X, Y]
means—from a set theory perspective—eitherX
orY
, 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.0
to anint
. If coercion is not desired theAny
type can be used with the caveat that values will not be type checked without additionalvalidation.
To pass arguments to the generated marshmallow fields (e.g.,validate
,load_only
,dump_only
, etc.),pass them to themetadata
argument of thefield
function.
Note that starting with version 4, marshmallow will disallow passing arbitrary arguments, so anyadditional metadata should itself be put in its ownmetadata
dict:
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)
marshmallow_dataclass
provides a@dataclass
decorator that behaves like the standard library's@dataclasses.dataclass
and adds aSchema
attribute 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.Schema
property is added dynamically, it can confuse type checkers.To avoid that, you can declareSchema
as aClassVar
.
fromtypingimportClassVar,Typefrommarshmallow_dataclassimportdataclassfrommarshmallowimportSchema@dataclassclassPoint:x:floaty:floatSchema:ClassVar[Type[Schema]]=Schema
It is also possible to derive all schemas from your ownbase Schema class(seemarshmallow's documentation about extendingSchema
).This allows you to implement custom (de)serializationbehavior, for instance specifying a custom mapping between your classes and marshmallow fields,or renaming fields on serialization.
classBaseSchema(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 field
importmarshmallowimportmarshmallow_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_schema
tomarshmallow_dataclass.dataclass
.
@marshmallow_dataclass.dataclass(base_schema=UppercaseSchema)classSample:my_text:strmy_int:int
Seemarshmallow's documentation about extendingSchema
.
This library allows you to specifycustomized marshmallow fields using python's Annoted typePEP-593.
fromtypingimportAnnotatedimportmarshmallow.fieldsasmfimportmarshmallow.validateasmvIPv4=Annotated[str,mf.String(validate=mv.Regexp(r"^([0-9]{1,3}\\.){3}[0-9]{1,3}$"))]
You can also pass a marshmallow field class.
fromtypingimportAnnotatedimportmarshmallowfrommarshmallow_dataclassimportNewTypeEmail=Annotated[str,marshmallow.fields.Email]
For convenience, some custom types are provided:
frommarshmallow_dataclass.typingimportEmail,Url
When using Python 3.8, you must importAnnotated
from the typing_extensions package
# Version agnostic import code:ifsys.version_info>= (3,9):fromtypingimportAnnotatedelse:fromtyping_extensionsimportAnnotated
NewType is deprecated in favor or type aliases using Annotated, as described above.
This library exports aNewType
function to create types that generatecustomized marshmallow fields.
Keyword arguments toNewType
are 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)
Note: if you are usingmypy
, you will notice thatmypy
throws an error if a variable defined withNewType
is used in a type annotation. To resolve this, add themarshmallow_dataclass.mypy
pluginto yourmypy
configuration, e.g.:
[mypy]plugins = marshmallow_dataclass.mypy# ...
Meta
options are set the same way as a marshmallowSchema
.
frommarshmallow_dataclassimportdataclass@dataclassclassPoint:x:floaty:floatclassMeta:ordered=True
The project documentation is hosted on GitHub Pages:https://lovasoa.github.io/marshmallow_dataclass/
To install this project and make changes to it locally, follow the instructions inCONTRIBUTING.md
.
About
Automatic generation of marshmallow schemas from dataclasses.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.