Package: preconvert
Read Latest Documentation-Browse GitHub Code RepositoryPreconvert is a library that extends existing serializiers (json, simplejson, bson, msgpack, ..) to be capable of convertingallthe types you use.
It accomplishes this by efficiently preconverting just the types the serializers aren't aware of (things like dataclasses and namedtuples) into basic built-in types that all
serializers can understand. It then provides a mechanism for you to build custom preconverters, and preconvert_plugins that automatically take effect when installed via pip.QuickstartInstall preconvert using pip:pip3 install preconvertReplace existing json (or other serialization library) with preconvert equivalent:from preconvert.output import simplejson as json

 ...

 json.dumps(MY_COMPLEX_OBJECT_WITH_DATA_CLASSSES)Define preconverters for any custom types, even if they aren't under your control:import numpy
 from preconvert import json


 class Employee:

     def __init__(self, first_name, last_name):
         self.first_name = first_name
         self.last_name = last_name

     def __preconvert__(self):
         return {'name': {'first': self.first_name, 'last': self.last_name}}


 @preconvert.converter(numpy.integer)
 def numpy_integer_to_python_int(numpy_int):
     return int(numpy_int)


 json.dumps({
     'employee': Employee('Timothy', 'Crosley'),
     'height_inches': numpy.int_(73)
 })Enjoy a more comprehensive and configurable serializer!Why?Have you ever tried tojson.dumpsa data structure, only to be surprised when your DataClass throws an exception, or your namedtuple outputs as a list?
Preconvert was created to solve this problem across common serialization formats.Before preconvert:importsysimportjsonfromdataclassesimportdataclass@dataclassclassInventoryItem:"""Class for keeping track of an item in inventory."""name:strunit_price:floatquantity_on_hand:int=0deftotal_cost(self)->float:returnself.unit_price*self.quantity_on_handmy_store_inventory=[InventoryItem("beer",unit_price=0.0,quantity_on_hand=sys.maxsize),InventoryItem("bacon",unit_price=2.5,quantity_on_hand=3)]json.dumps(my_store_inventory)output>>>177178-->179raiseTypeError(f'Object of type{o.__class__.__name__}'180f'is not JSON serializable')181TypeError:ObjectoftypeInventoryItemisnotJSONserializableD:After preconvert:importsysimportjsonfrompreconvert.outputimportjson@dataclassclassInventoryItem:"""Class for keeping track of an item in inventory."""name:strunit_price:floatquantity_on_hand:int=0deftotal_cost(self)->float:returnself.unit_price*self.quantity_on_handmy_store_inventory=[InventoryItem("beer",unit_price=0.0,quantity_on_hand=sys.maxsize),InventoryItem("bacon",unit_price=2.5,quantity_on_hand=3)]json.dumps(my_store_inventory)>>>[{"name":"beer","unit_price":0.0,"quantity_on_hand":9223372036854775807},{"name":"bacon","unit_price":2.5,"quantity_on_hand":3}]:DDesign goals:Easy utilization from existing projectsEnable conversion from complex to simple types independant of desired output formatProvide built in conversion for common types that are not universally supported (dataclasses, namedtuple, etc...)Provide a way to build custom preconverts or override built-in preconvertsAbility to build preconverts that are dependent on the destination formatMinimal overhead when utilized with common serialization formatsHow do I use this?If your project uses one of our built-in supported serializers (json, msgpak, bson)
you can simply replace your existing serializer import with a preconvert one:from preconvert.outputs import jsonORfrom preconvert.outputs import simplejson as jsonORfrom preconvert.outputs import msgpackORfrom preconvert.outputs import bsonIf not you can inject preconvert before usage of any other serializers, often by setting adefaultoron_onknownparameter:import preconvert
import my_serializer

my_serializer.dumps(default=preconvert.default_serializable)How do I extend this?Want to add preconversion to your own custom types? For OOP projects, one easy way to do this is to add a__preconvert__method to your object:classMyCustomClass(object):def__init__(self,first_name,children=()):self.first_name=first_nameself.children=childrendef__jsonifiable__(self)return{'first':self.first_name,'children':children}For other entities, such as objects you do not control, you can register a new preconvert using thepreconvert.converterdecorator:importpreconvert@preconvert.converter(SomeFrameworkObject)defconvert_framework_object(instance):return{'name':instance.name}You can also, optionally, specify preconversions per an intended serialization format:importpreconvert@preconvert.json(SomeFrameworkObject)defconvert_framework_object(instance):return{'json':{'name':instance.name}}@preconvert.msgpack(SomeFrameworkObject)defconvert_framework_object(instance):return['name',instance.name]Finally, you can resister any modules that contain converters to package 'preconvert.converters' entrypoints, and they will take effect automatically as long as the package that contains them is installed.
See thepreconvert_numpyfor an example of how this works.