1-step serialization to/from json: handles user classes and circular refs
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jsserialize-0.5.tar.gz.
File metadata
- Download URL: jsserialize-0.5.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using 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
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a19c0b3445fe1e28dbcdbf38c3440e8d04ac7d3c681261a5a97242d6bb971423
|
|
| MD5 |
4b8370f513dcc364775bf9d68de6fd36
|
|
| BLAKE2b-256 |
1fc09074f387dc9df73904bfb9ca4c47fa0a0ed26508fcd79a1999af87dc8c94
|
File details
Details for the file jsserialize-0.5-py3-none-any.whl.
File metadata
- Download URL: jsserialize-0.5-py3-none-any.whl
- Upload date:
- Size: 6.5 kB
- Tags: Python 3
- Uploaded using 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
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27c9219a49b8e2402dba442ea5edebb4ceb25940c5b9bd064002b4edf72d13e3
|
|
| MD5 |
ce831141c7df2e5e89e0aaf51c02d5cc
|
|
| BLAKE2b-256 |
8f13b313f19bb920cc7f2b894839badea1128bfbd948984353db342ad228a15d
|