Package: jsondataclass
jsondataclassjsondataclassis a library that makes it easy for you to convert of dataclasses (PEP 557) to and from JSON.Installationpip3 install jsondataclassRequirementspython>=3.7Quick startfromdataclassesimportdataclassfromjsondataclassimportto_json,from_json@dataclassclassMovie:name:stryear:intcounty:strmovie=Movie("Terminator: Dark Fate",2019,"USA")print(to_json(movie))# {"name": "Terminator: Dark Fate", "year": 2019, "county": "USA"}json_str='{"name": "Terminator: Dark Fate", "year": 2019, "county": "USA"}'print(from_json(json_str,Movie))# Movie(name='Terminator: Dark Fate', year=2019, county='USA')Supported typesstr, int, bool, dict, list, tuplenested dataclassestyping.Listtyping.Tupletyping.Dicttyping.Optionaltyping.Uniontyping.Literal (python >= 3.8 required)datetime.datetimedatetime.datedatetime.timetimestampEnumDecimalUsageThe primary functions to use arefrom_jsonandto_json. There is also a classDataClassMapperwith methodsfrom_jsonandto_jsonavailable that can be used to configure conversion operations.TheDataClassMapperinstance does not maintain any state while invoking Json operations. So, you are free to reuse the same object for multiple Json serialization and deserialization operations.Dataclass to JSONfromdataclassesimportdataclassfromjsondataclassimportto_json,DataClassMapper@dataclassclassUser:id:intname:struser=User(1,"John Doe")mapper=DataClassMapper()json_str=mapper.to_json(user)print(json_str)# {"id": 1, "name": "John Doe"}# orjson_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe"}Dataclass from JSONfromdataclassesimportdataclassfromjsondataclassimportfrom_json,DataClassMapper@dataclassclassUser:id:intname:strjson_str='{"id": 1, "name": "John Doe"}'mapper=DataClassMapper()user=mapper.from_json(json_str,User)print(user)# User(id=1, name='John Doe')# oruser=from_json(json_str,User)print(user)# User(id=1, name='John Doe')Dataclass to dictfromdataclassesimportdataclassfromjsondataclassimportto_dict,DataClassMapper@dataclassclassUser:id:intname:struser=User(1,"John Doe")mapper=DataClassMapper()dict_obj=mapper.to_dict(user)print(dict_obj)# {'id': 1, 'name': 'John Doe'}# ordict_obj=to_dict(user)print(dict_obj)# {'id': 1, 'name': 'John Doe'}Dataclass from dictfromdataclassesimportdataclassfromjsondataclassimportto_dict,DataClassMapper@dataclassclassUser:id:intname:struser=User(1,"John Doe")mapper=DataClassMapper()dict_obj=mapper.to_dict(user)print(dict_obj)# {'id': 1, 'name': 'John Doe'}# ordict_obj=to_dict(user)print(dict_obj)# {'id': 1, 'name': 'John Doe'}Nested dataclassfromdataclassesimportdataclassfromjsondataclassimportfrom_json,to_json@dataclassclassContactInfo:email:strphone_number:str@dataclassclassUser:id:intname:strinfo:ContactInfouser=User(1,"John Doe",ContactInfo("john@doe.com","+19999999"))print(to_json(user))# {"id": 1, "name": "John Doe", "info": {"email": "john@doe.com", "phone_number": "+19999999"}}json_str='{"id": 1, "name": "John Doe", "info": {"email": "john@doe.com", "phone_number": "+19999999"}}'print(from_json(json_str,User))# User(id=1, name='John Doe', info=ContactInfo(email='john@doe.com', phone_number='+19999999'))Field serialized namefromdataclassesimportdataclassfromjsondataclassimportfrom_json,to_json,jsonfield@dataclassclassUser:id:int=jsonfield("Id")name:str=jsonfield("Name")json_str='{"Id": 1, "Name": "John Doe"}'user=from_json(json_str,User)print(user)# User(id=1, name='John Doe')json_str=to_json(user)print(json_str)# {"Id": 1, "Name": "John Doe"}Optional fieldsfromdataclassesimportdataclassfromtypingimportOptionalfromjsondataclassimportfrom_json@dataclassclassUser:id:intname:stremail:Optional[str]json_str='{"id": 1, "name": "John Doe"}'user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', email=None)UnionsfromdataclassesimportdataclassfromtypingimportUnionfromjsondataclassimportfrom_json,to_json@dataclassclassUser:id:Union[int,str]name:strjson_str='{"id": 1, "name": "John Doe"}'user=from_json(json_str,User)print(user)# User(id=1, name='John Doe')json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe"}Generic collectionsfromdataclassesimportdataclassfromtypingimportList,Tuple,Dictfromjsondataclassimportfrom_json,to_json@dataclassclassMovie:genres:List[str]rating:Tuple[float,int]name:Dict[str,str]movie=Movie(["comedy","crime"],(5.6,100),{"en":"WALL-E","de":"WALL-E"})json_str=to_json(movie)print(json_str)# {"genres": ["comedy", "crime"], "rating": [5.6, 100], "name": {"en": "WALL-E", "de": "WALL-E"}}json_str='{"genres": ["comedy", "crime"], "rating": [5.6, 100], "name": {"en": "WALL-E", "de": "WALL-E"}}'movie=from_json(json_str,Movie)print(movie)# Movie(genres=['comedy', 'crime'], rating=(5.6, 100), name={'en': 'WALL-E', 'de': 'WALL-E'})LiteralsfromdataclassesimportdataclassfromtypingimportLiteralfromjsondataclassimportfrom_json,to_json@dataclassclassMovie:name:stryear:intrating:Literal[1,2,3,4,5]movie=Movie("Terminator: Dark Fate",2019,5)print(to_json(movie))# > {"name": "Terminator: Dark Fate", "year": 2019, "rating": 5}json_str='{"name": "Terminator: Dark Fate", "year": 2019, "rating": 5}'print(from_json(json_str,Movie))# > Movie(name='Terminator: Dark Fate', year=2019, rating=5)EnumsfromdataclassesimportdataclassfromenumimportEnumfromjsondataclassimportfrom_json,to_jsonclassRole(Enum):ADMIN=1STAFF=2GUEST=3@dataclassclassUser:id:intname:strrole:Roleuser=User(1,"John Doe",Role.ADMIN)json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "role": 1}json_str='{"id": 1, "name": "John Doe", "role": 1}'user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', role=<Role.ADMIN: 1>)DecimalDecimal type can be decerialized from integer, float or string, but is serialized always to string.fromdataclassesimportdataclassfromdecimalimportDecimalfromjsondataclassimportfrom_json,to_json@dataclassclassUser:id:intname:strsalary:Decimaluser=User(1,"John Doe",Decimal("11.22"))json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "salary": "11.22"}json_str='{"id": 1, "name": "John Doe", "salary": "11.22"}'user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', salary=Decimal('11.22'))datetime, date, timeSerialization ofdatetime,dateandtimeobjects are performed usingisoformat(), andfromisoformat()are used for deserialization.fromdataclassesimportdataclassfromdatetimeimportdatetime,date,timefromjsondataclassimportfrom_json,to_json,DataClassMapper,jsonfield@dataclassclassUser:id:intname:strlast_login:datetimebirthday:datelocal_time:timeuser=User(1,"John Doe",datetime.now(),date(2000,1,1),time(0,0,0,0))json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "last_login": "2019-10-31T18:53:47.615534", "birthday": "2000-01-01", "local_time": "00:00:00"}user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', last_login=datetime.datetime(2019, 10, 31, 18, 54, 35, 688288), birthday=datetime.date(2000, 1, 1), local_time=datetime.time(0, 0))But you can specify format viaDataClassMapperinstance.mapper=DataClassMapper()mapper.datetime_format="%m/%d/%y %H:%M:%S"mapper.date_format="%m/%d/%y"mapper.time_format="%H:%M"user=User(1,"John Doe",datetime.now(),date(2000,1,1),time(0,0,0,0))json_str=mapper.to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "last_login": "10/31/19 18:59:11", "birthday": "01/01/00", "local_time": "00:00"}user=mapper.from_json(json_str,User)print(user)# User(id=1, name='John Doe', last_login=datetime.datetime(2019, 10, 31, 18, 59, 11), birthday=datetime.date(2000, 1, 1), local_time=datetime.time(0, 0))Or viajsonfieldfunction.@dataclassclassUser:id:intname:strlast_login:datetime=jsonfield(serializer_args=("%y/%m/%d%H:%M:%S",))birthday:date=jsonfield(serializer_args=("%y/%m/%d",))local_time:time=jsonfield(serializer_args=("%I:%M %p",))user=User(1,"John Doe",datetime.now(),date(2000,1,1),time(0,0,0,0))json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "last_login": "19/10/31 19:00:58", "birthday": "00/01/01", "local_time": "12:00 AM"}user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', last_login=datetime.datetime(2019, 10, 31, 19, 0, 58), birthday=datetime.date(2000, 1, 1), local_time=datetime.time(0, 0))TimestampBy default, deserialization of timestamp result datetime naive object.fromdataclassesimportdataclassfromdatetimeimportdatetime,timezonefromjsondataclassimportfrom_json,to_json,jsonfield@dataclassclassUser:id:intname:strlast_login:datetime.timestampuser=User(1,"John Doe",datetime.now())json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "last_login": 1572541610}user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', last_login=datetime.datetime(2019, 10, 31, 19, 7, 41))You can specify timezone usingjsonfieldfunction.@dataclassclassUser:id:intname:strlast_login:datetime.timestamp=jsonfield(serializer_kwargs={"timezone":timezone.utc})user=User(1,"John Doe",datetime.now())json_str=to_json(user)print(json_str)# {"id": 1, "name": "John Doe", "last_login": 1572541956}user=from_json(json_str,User)print(user)# User(id=1, name='John Doe', last_login=datetime.datetime(2019, 10, 31, 17, 12, 36, tzinfo=datetime.timezone.utc))Forward Referencesfromdataclassesimportdataclassfromjsondataclassimportfrom_json,to_jsonfromjsondataclass.utilsimportset_forward_refs@dataclassclassUser:id:intname:strinfo:"ContactInfo"@dataclassclassContactInfo:email:strphone_number:strset_forward_refs(User,{"ContactInfo":ContactInfo})user=User(1,"John Doe",ContactInfo("john@doe.com","+19999999"))print(to_json(user))# {"id": 1, "name": "John Doe", "info": {"email": "john@doe.com", "phone_number": "+19999999"}}json_str='{"id": 1, "name": "John Doe", "info": {"email": "john@doe.com", "phone_number": "+19999999"}}'print(from_json(json_str,User))# User(id=1, name='John Doe', info=ContactInfo(email='john@doe.com', phone_number='+19999999'))Custom Serialization and DeserializationSometimes default representation is not what you want.DataClassMapperallows you to register your own custom serializers.fromdataclassesimportdataclassfromtypingimportTypefromjsondataclassimportDataClassMapper,jsonfield,to_json,from_jsonfromjsondataclass.serializersimportSerializerclassRating:def__init__(self,rating,vote_count):self.rating=ratingself.vote_count=vote_countdef__repr__(self):returnf"Rating(rating={self.rating}, vote_count={self.vote_count})"classRatingSerializer(Serializer[list]):defserialize(self,data:Rating)->list:return[data.rating,data.vote_count]defdeserialize(self,data:list,type_:Type[Rating])->Rating:returnRating(*data)@dataclassclassMovie:name:stryear:intrating:Ratingmovie=Movie("Terminator: Dark Fate",2019,Rating(5,100))mapper=DataClassMapper()mapper.register_serializer(Rating,RatingSerializer)json_str=mapper.to_json(movie)print(json_str)# {"name": "Terminator: Dark Fate", "year": 2019, "rating": [5, 100]}json_str='{"name": "Terminator: Dark Fate", "year": 2019, "rating": [5, 100]}'movie=mapper.from_json(json_str,Movie)print(movie)# Movie(name='Terminator: Dark Fate', year=2019, rating=Rating(rating=5, vote_count=100))Or you can set your serializer on per-field level.@dataclassclassMovie:name:stryear:intrating:Rating=jsonfield(serializer_class=RatingSerializer)movie=Movie("Terminator: Dark Fate",2019,Rating(5,100))json_str=to_json(movie)print(json_str)# {"name": "Terminator: Dark Fate", "year": 2019, "rating": [5, 100]}json_str='{"name": "Terminator: Dark Fate", "year": 2019, "rating": [5, 100]}'movie=from_json(json_str,Movie)print(movie)# Movie(name='Terminator: Dark Fate', year=2019, rating=Rating(rating=5, vote_count=100))Also, you can override builtin serializers.classUpperStringSerializer(Serializer[str]):defserialize(self,data:str)->str:returndata.upper()defdeserialize(self,data:str,type_:Type[str])->str:returndata.upper()@dataclassclassMovie:name:stryear:intmovie=Movie("Terminator: Dark Fate",2019)mapper=DataClassMapper()mapper.register_serializer(str,UpperStringSerializer)json_str=mapper.to_json(movie)print(json_str)# {"name": "TERMINATOR: DARK FATE", "year": 2019}json_str='{"name": "Terminator: Dark Fate", "year": 2019}'movie=mapper.from_json(json_str,Movie)print(movie)# Movie(name='TERMINATOR: DARK FATE', year=2019)@dataclassclassMovie:name:str=jsonfield(serializer_class=UpperStringSerializer)year:intmovie=Movie("Terminator: Dark Fate",2019)json_str=mapper.to_json(movie)print(json_str)# {"name": "TERMINATOR: DARK FATE", "year": 2019}json_str='{"name": "Terminator: Dark Fate", "year": 2019}'movie=mapper.from_json(json_str,Movie)print(movie)# Movie(name='TERMINATOR: DARK FATE', year=2019)History0.1.0 (2019-11-01)First release on PyPI.0.2.0 (2019-11-01)Decimal type support.