Skip to main content

jsserialize.py: serialize python data structures as json strings

This module defines the functions "encode" and "decode", which encode/decode data to and from json strings. Unlike the functions in the standard "json" package, these can automatically handle user-defined classes and circular references.

	jsserialize functions:

	encode(data,custom_encode=None):
		Encode "data" to a json string. 
		Use "custom_encode" to override the default encoding of objects.
		Returns: json string encoding of "data"

	decode(jsonstr,custom_decode=None):
		Recreate data from a json string ("jsonstr").  
		Use "custom_decode" to override the default decoding of objects.
		Returns: the recreated data

Custom encode/decode:

When we encode an object, we create a dictionary of name/value pairs giving the object's attributes. This contains the info needed to rebuild the object at decode time. The default handling requires that the object's class have a default constructor (ie., a constructor that doesn't accept arguments, "MyClass()"). If that's not possible, you can pass a custom encoder to "encode" (and custom decoder to "decode").

The custom encoder accepts an object and returns a dictionary. Returning "None" means the object wasn't encoded, and we should use the default handling. The custom decoder accepts a class name and dictionary and returns an object. Returning "None" means it wasn't decoded, and we should use the default handling. Here's an example: we encode/decode a date from the python datetime module.

	def custom_encode(obj):
		if obj.__class__.__name__ == 'date':
    		# 'obj.isoformat()' returns a str
    		return {'isoformat': obj.isoformat()}
		return None

	def custom_decode(classname,dct):
		if classname == 'datetime.date':
    		# "fromisoformat" is class method that creates
    		# a date object from an isoformat string
    		return datetime.date.fromisoformat(dct['isoformat'])
		return None

Note: in "custom_decode", "classname" is the full classname (module name, followed by the name in the class definition).

Requirements and Installation

Requires Python 3. Install with pip:

	pip install jsserialize

Dev Notes

This repository contains "jsserialize.py". Additonal files ("setup.py", "setup.cfg", and "hwoto_pypi.txt") are for uploading the module to pypi.

Sample Code

	import jsserialize
	
	# We need some data to encode. We'll use a tree built from Nodes.
	# The base class None has a "parent" attribute and a list "kids"
	# containing child nodes. From the base class we define 2 subclasses,
	# "A" and "B". The A class has a "color" attribute whose value is a string.
	# The B class has a "date" attribute whose value is an object of class
	# "date", from the standard python "datetime" module.
	
	import datetime
	nodeid = 0
	class Node():
		def __init__(self):
    		global nodeid
    		self.id = str(nodeid)
    		nodeid += 1
    		self.parent = None
    		self.kids = []
	
		def add_kid(self,kid):
    		self.kids.append(kid)
    		kid.parent = self
	
		def attrs_to_str(self):
    		# child classes override this to return a string giving
    		# attribute name/values.
    		return ''
	
		def printme(self,indent=''):
    		pid = "None" if self.parent is None else self.parent.id
    		print('%s%s %s parent:%s %s' %
        		(indent,self.__class__.__name__,
        		self.id,pid,self.attrs_to_str()))
    		indent += '  '
    		for k in self.kids:
        		k.printme(indent)
	
	class A(Node):
		def __init__(self,color='red'):
    		super().__init__()
    		self.color = color
	
		def attrs_to_str(self):
    		return 'color:%s' % self.color
	
	class B(Node):
		def __init__(self,date=None):
    		super().__init__()
    		self.date = date
	
		def attrs_to_str(self):
    		return 'date:%s' % (
        		'None' if self.date is None else self.date.isoformat())
	
	# make the data we'll encode/decode: a tree built from A and B nodes.
	def make_data():
		root = A()
		kid1 = A('yellow')
		kid2 = B(datetime.date.fromordinal(1))
		root.add_kid(kid1)
		root.add_kid(kid2)
		kid2.add_kid( A('blue') )
		kid2.add_kid( B(datetime.date.today()) )
		return root
	
	# Here are the custom encode/decode functions. We need them
	# because our data includes objects of class "date"
	# from the python standard "datetime" module, and jsserialize
	# doesn't know how to encode/decode objects of that class.
	# Note that these encode/decode functions only need to handle
	# "date" objects -- our data also includes objects of class "A"
	# and "B", but jsserialize can handle them without our help. (For this
	# to work, we have to make sure our user-defined classes have
	# default constructors).
	
	def custom_encode(obj):
		if obj.__class__.__name__ == 'date':
    		# 'obj.isoformat()' returns a str
    		return {'isoformat': obj.isoformat()}
		# returning None tells jsserialize: we didn't encode the
		# object, you do it.
		return None
	
	def custom_decode(classname,dct):
		# Notice that classname is the "full" name for the class:
		# module name, followed the name that appeared in the
		# class definition.
		if classname == 'datetime.date':
    		# "fromisoformat" is class method that creates
    		# a date object from an isoformat string
    		return datetime.date.fromisoformat(dct['isoformat'])
		# returning None tells jsserialize: we didn't decode the
		# object, you do it.
		return None
	
	def test():
		# create data to be encoded: a tree built from nodes
		data = make_data()
		print("data to be encoded:")
		data.printme()
	
		# get the json string encoding
		json_str = jsserialize.encode(data,custom_encode=custom_encode)
	
		# decode the json_str, recreating the data
		data2 = jsserialize.decode(json_str, custom_decode=custom_decode)
		print("\ndecoded data:")
		data2.printme()
	
		# print the json string
		print("\njson string:")
		print(json_str)
	
	if __name__=='__main__':
		test()

Who do I talk to?

Al Cramer (ac2.7@1828@gmail.com)

Copyright Al Cramer 2022

Metadata

Release files for jsserialize 0.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jsserialize 0.5
File Size Uploaded
jsserialize-0.5.tar.gz 6.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jsserialize 0.5
File Interpreter ABI Platform
jsserialize-0.5-py3-none-any.whl Python 3 none any Details

Total release size: 12.7 kB

Release files / jsserialize-0.5.tar.gz

Download URL jsserialize-0.5.tar.gz
Size 6.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a19c0b3445fe1e28dbcdbf38c3440e8d04ac7d3c681261a5a97242d6bb971423
BLAKE2b-256 checksum
How to use checksums
1fc09074f387dc9df73904bfb9ca4c47fa0a0ed26508fcd79a1999af87dc8c94
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.0.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.9.5

Release files / jsserialize-0.5-py3-none-any.whl

Download URL jsserialize-0.5-py3-none-any.whl
Size 6.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
27c9219a49b8e2402dba442ea5edebb4ceb25940c5b9bd064002b4edf72d13e3
BLAKE2b-256 checksum
How to use checksums
8f13b313f19bb920cc7f2b894839badea1128bfbd948984353db342ad228a15d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.0.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.9.5

Release history Release notifications | RSS feed

This release

0.5 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page