Package: jsonplus
Serialization of Python types to JSON that “just works”.Forget errors like:TypeError: datetime.datetime(...) is not JSON serializableIn addition to (de-)serialization of basic types (provided bysimplejson),jsonplusprovides support forexact(de-)serialization of other commonly used types, like:tuple/namedtuple,set/frozenset,complex/decimal.Decimal/fractions.Fraction,
anddatetime/date/time/timedelta.If the exact representation of types is not your cup of tea, and all you wish
for is thejson.dumpsto work on your data structure with non-basic types,
accepting the loss of “type-precision” along the way, than you can use thecompatibilitymode (thread-localjsonplus.prefer_compat(), or
per-call overridejsonplus.dumps(...,exact=False)).Installationjsonplusis available as a Python package. To install it, simply type:$ pip install jsonplusUsageYou can treatjsonplusas a friendlydrop-inreplacement forjson/simplejson.>>>importjsonplusasjson>>>x=json.loads('{"a":1,"b":2}')>>>y=json.dumps(x,indent=4)>>>z=json.pretty(x)ExamplesLet’s start with that beloveddatetime.>>>importjsonplusasjson>>>fromdatetimeimportdatetime>>>json.dumps({..."x":[4,3],..."t":datetime.now()...})'{"x":[4,3],"t":{"__class__":"datetime","__value__":"2013-09-06T23:38:55.819791"}}'>>>json.loads(_){u'x':[4,3],u't':datetime.datetime(2013,9,6,23,38,55,819791)}Similarly for otherdatetime.*types, liketimedelta,date, andtime:>>>fromdatetimeimporttimedelta,date,time>>>print(json.pretty({"dt":timedelta(0,1234567,123),"d":date.today(),"t":datetime.now().time()})){"d":{"__class__":"date","__value__":"2013-09-22"},"dt":{"__class__":"timedelta","__value__":{"days":14,"microseconds":123,"seconds":24967}},"t":{"__class__":"time","__value__":"23:33:16.335360"}}Also,setandcomplex:>>>json.dumps([set(range(3)),1+2j])'[{"__class__":"set","__value__":[0,1,2]},{"__class__":"complex","__value__":{"real":1.0,"imag":2.0}}]'>>>json.loads(_)[set([0,1,2]),(1+2j)]tupleandnamedtupleare also preserved:>>>fromcollectionsimportnamedtuple>>>Point=namedtuple('Point',['x','y'])>>>data=json.pretty({"vect":(1,2,3),"dot":Point(3,4)})>>>print(data){"dot":{"__class__":"namedtuple","__value__":{"fields":["x","y"],"name":"Point","values":[3,4]}},"vect":{"__class__":"tuple","__value__":[1,2,3]}}>>>json.loads(data){'vect':(1,2,3),'dot':Point(x=3,y=4)}Compatibility modeAll types supported in the exact mode are also supported in the compatibility
mode. JSON representation differs, however.In the exact mode,typeandvalueare encoded withJSON Object’s__class__and__value__keys, while in the compatibility mode,values are “rounded off” to the closest JSON type.For example,tupleandsetare represented withJSON Array, andnamedtupleis coded as a plainJSON Object.Decimalis
represented asJSON Numberwith arbitrary precision (which is lost if
decoded asfloat).To switch between theexactandcompatibilitymodes, use the
(thread-local) functionsprefer_exact()andprefer_compat(), or calldumps(...,exact=False):>>>importjsonplusasjson>>>json.prefer_compat()# or:>>>json.prefer(json.COMPAT)# per-instance override:>>>json.dumps(obj,exact=False)# to go back to (default) exact coding:>>>json.prefer_exact()The abovetuple/namedtuple/datetimeexamples run in the compatibility
coding mode result with:>>>json.prefer_compat()>>>print(json.pretty({"vect":(1,2,3),"dot":Point(3,4)})){"point":{"x":3,"y":4},"vector":[1,2,3]}>>>json.dumps({"now":datetime.now()})'{"now":"2017-01-26T00:37:40.293963"}'So, to be able to properly decode values in the compatibility mode, some
additional context will have to be provided to the decoder.Adding user typesSupport for user/custom types can easily be added with@jsonplus.encoderand@jsonplus.decoderdecorators.For example, to enable serialization of your type namedmytypein exact mode
(to add compat-mode serialization, appendexact=Falsein decorator):@jsonplus.encoder('mytype')defmytype_exact_encoder(myobj):returnmyobj.to_json()@jsonplus.decoder('mytype')defmytype_decoder(value):returnmytype(value,reconstruct=True,...)If detection of object class is more complex than a simple classname comparison,
if you need to use a predicate function, simply addpredicate=...to theencoderdecorator. For example:@jsonplus.encoder('BaseClass',lambdaobj:isinstance(obj,BaseClass))defall_derived_classes_encoder(derived):returnderived.base_encoder()