Source code for simpleml.persistables.serializing

'''
Module to define the classes that support serialization for all JSON columns

A lot of persistable subclasses try to persist objects that cannot be natively serialized
in a database. This attempts to define a custom pattern to serialize them and
subsequently deserialize on load
'''

__author__ = 'Elisha Yadgaran'


import json
import dill as pickle
import codecs
import sys

try:  # Py2/3 compatibility
    basestring
except NameError:
    basestring = str


[docs]class JSONSerializer(json.JSONEncoder):
[docs] def default(self, obj): # Otherwise try defaults or fallback to pickle try: return super(JSONSerializer, self).default(obj) except TypeError: return 'pickle_serialized->' + codecs.encode(pickle.dumps(obj), "base64").decode()
[docs]def object_hook(data, ignore_dicts=False): # if this is a string, check for pickled if isinstance(data, basestring) and len(data) > 19: if data[:19] == 'pickle_serialized->': return pickle.loads(codecs.decode(data[19:].encode(), "base64")) # if this is a list of values, return list of deserialized values if isinstance(data, list): return [object_hook(item, ignore_dicts=True) for item in data] # if this is a dictionary, return dictionary of deserialized keys and values # but only if we haven't already deserialized it if isinstance(data, dict) and not ignore_dicts: return { object_hook(key, ignore_dicts=True): object_hook(value, ignore_dicts=True) for key, value in data.items() } # if it's anything else, return it in its original form return data
[docs]def custom_dumps(data): # Unfortunately JSON doesnt support dict keys as ints so they will automatically # get converted. Hopefully this wont be an issue in SimpleML, but be aware... return json.dumps(data, cls=JSONSerializer, ensure_ascii=False)
[docs]def custom_loads(data): # Need the extra nesting because json loads only passes nested dict objects to object_hook # Python 2 strings have a decode method, python 3 doesn't if sys.version_info[0] == 2: return object_hook(json.loads(data.decode('utf-8'), object_hook=object_hook), ignore_dicts=True) else: return object_hook(json.loads(data, object_hook=object_hook), ignore_dicts=True)