Skip to content

Instantly share code, notes, and snippets.

@neolitec
Created June 20, 2019 19:28
Show Gist options
  • Save neolitec/5400b919a4b62903c00f52e82bfb97a8 to your computer and use it in GitHub Desktop.
Save neolitec/5400b919a4b62903c00f52e82bfb97a8 to your computer and use it in GitHub Desktop.
Python JSON Serializer / Deserializer
from .BaseDecoder import *
from .BaseEncoder import *
import json
def attributes(attrs):
def decorator(Cls):
class ThisDecoder(BaseDecoder):
ATTRIBUTES = attrs
def __init__(self, *args, **kwargs):
BaseDecoder.__init__(self, Cls)
class ThisEncoder(BaseEncoder):
ATTRIBUTES = attrs
def __init__(self, *args, **kwargs):
BaseEncoder.__init__(self, Cls)
Cls.Decoder = ThisDecoder
Cls.Encoder = ThisEncoder
Cls.from_json = staticmethod(lambda stringJson: json.loads(stringJson, cls=ThisDecoder))
Cls.to_json = lambda self: json.dumps(self, cls=ThisEncoder)
Cls.__str__ = lambda self: str(self.__dict__)
return Cls
return decorator
import json
class BaseDecoder:
def __init__(self, clazz):
json.JSONDecoder.__init__(self)
self.clazz = clazz
def decode(self, dct):
if type(dct) is str:
dct = json.loads(dct)
return self.decode_dict(dct)
def decode_dict(self, dct):
o = self.clazz()
for attr_name, attr_type in self.ATTRIBUTES.items():
value = dct.get(attr_name)
if value is None:
continue
if type(value) is dict:
value = dct.get(attr_name, {})
if type(attr_type) is list and type(value) is list and len(attr_type) and len(value):
item_type = attr_type[0]
setattr(o, attr_name, list(map(lambda item: get_converted_object(item_type, item), value)))
else:
setattr(o, attr_name, get_converted_object(attr_type, value))
return o
def get_converted_object(attr_type, value):
if hasattr(attr_type, 'Decoder'):
decoder = attr_type.Decoder()
return decoder.decode_dict(value)
else:
return value
import json
class BaseEncoder(json.JSONEncoder):
def __init__(self, clazz):
json.JSONEncoder.__init__(self)
self.clazz = clazz
def default(self, obj):
d = dict()
for attr_name, attr_type in self.ATTRIBUTES.items():
value = getattr(obj, attr_name, None)
if value is None:
continue
if type(attr_type) is list and len(attr_type) and len(value):
item_type = attr_type[0]
d[attr_name] = list(map(lambda item: get_converted_object(item_type, item), value))
else:
d[attr_name] = get_converted_object(attr_type, value)
return d
def get_converted_object(attr_type, value):
if hasattr(attr_type, 'Encoder'):
encoder = attr_type.Encoder()
return encoder.default(value)
else:
return value
from models import *
json_string = """{
"name": "x3.large",
"tags": [{
"name": "foo"
}],
"network": {
"name": "eth0",
"speed": "1000"
},
"storage": {
"type": "ssd",
"size": "1TB"
}
}"""
@attributes({
'name': str,
'speed': str
})
class Network:
pass
@attributes({
'type': str,
'size': str
})
class Storage:
pass
@attributes({
'name': str
})
class Tag:
pass
@attributes({
'name': str,
'tags': [Tag],
'network': Network,
'storage': Storage
})
class Server:
pass
s = Server.from_json(json_string)
print(s)
print(s.network)
json = s.to_json()
print(json)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment