128 lines
3.5 KiB
Python
128 lines
3.5 KiB
Python
import json
|
|
|
|
import core.utils
|
|
from core.global_symbols import NotInit, NotFound, Removed
|
|
from sheerkapickle import tags, utils, handlers
|
|
|
|
|
|
def decode(sheerka, obj):
|
|
return SheerkaUnpickler(sheerka).restore(json.loads(obj))
|
|
|
|
|
|
class SheerkaUnpickler:
|
|
def __init__(self, sheerka):
|
|
self.sheerka = sheerka
|
|
self.objs = []
|
|
|
|
def restore(self, obj):
|
|
if has_tag(obj, tags.ID):
|
|
return self._restore_id(obj)
|
|
|
|
if has_tag(obj, tags.TUPLE):
|
|
return self._restore_tuple(obj)
|
|
|
|
if has_tag(obj, tags.CUSTOM):
|
|
return self._restore_custom(obj)
|
|
|
|
if has_tag(obj, tags.SET):
|
|
return self._restore_set(obj)
|
|
|
|
if has_tag(obj, tags.ENUM):
|
|
return self._restore_enum(obj)
|
|
|
|
if has_tag(obj, tags.OBJECT):
|
|
return self._restore_obj(obj)
|
|
|
|
if utils.is_list(obj):
|
|
return self._restore_list(obj)
|
|
|
|
if utils.is_dictionary(obj):
|
|
return self._restore_dict(obj)
|
|
|
|
return obj
|
|
|
|
def _restore_list(self, obj):
|
|
return [self.restore(v) for v in obj]
|
|
|
|
def _restore_tuple(self, obj):
|
|
return tuple([self.restore(v) for v in obj[tags.TUPLE]])
|
|
|
|
def _restore_custom(self, obj):
|
|
if obj[tags.CUSTOM] == NotInit.value:
|
|
instance = NotInit
|
|
elif obj[tags.CUSTOM] == NotFound.value:
|
|
instance = NotFound
|
|
elif obj[tags.CUSTOM] == Removed.value:
|
|
instance = Removed
|
|
else:
|
|
raise KeyError(f"unknown {obj[tags.CUSTOM]}")
|
|
|
|
self.objs.append(instance)
|
|
return instance
|
|
|
|
def _restore_set(self, obj):
|
|
return set([self.restore(v) for v in obj[tags.SET]])
|
|
|
|
def _restore_enum(self, obj):
|
|
instance = core.utils.decode_enum(obj[tags.ENUM])
|
|
self.objs.append(instance)
|
|
return instance
|
|
|
|
def _restore_dict(self, obj):
|
|
data = {}
|
|
for k, v in obj.items():
|
|
resolved_key = self._resolve_key(k)
|
|
data[resolved_key] = self.restore(v)
|
|
return data
|
|
|
|
def _restore_id(self, obj):
|
|
try:
|
|
return self.objs[obj[tags.ID]]
|
|
except IndexError:
|
|
pass
|
|
|
|
def _restore_obj(self, obj):
|
|
handler = handlers.get(obj[tags.OBJECT])
|
|
|
|
if handler:
|
|
handler = handler(self.sheerka, self)
|
|
instance = handler.new(obj)
|
|
self.objs.append(instance)
|
|
instance = handler.restore(obj, instance)
|
|
else:
|
|
# KSI 202011: Hack because Property is removed
|
|
# To suppress asap
|
|
if obj[tags.OBJECT] == "core.concept.Property":
|
|
return self.restore(obj["value"])
|
|
|
|
cls = core.utils.get_class(obj[tags.OBJECT])
|
|
instance = cls.__new__(cls)
|
|
self.objs.append(instance)
|
|
|
|
for k, v in obj.items():
|
|
if k == tags.OBJECT:
|
|
continue
|
|
value = self.restore(v)
|
|
setattr(instance, k, value)
|
|
|
|
return instance
|
|
|
|
def _resolve_key(self, key):
|
|
|
|
if key == "null":
|
|
return None
|
|
|
|
concept_key, concept_id = core.utils.unstr_concept(key)
|
|
if concept_key is not None:
|
|
return self.sheerka.new((concept_key, concept_id)) if concept_id else self.sheerka.new(concept_key)
|
|
|
|
as_enum = core.utils.decode_enum(key)
|
|
if as_enum is not None:
|
|
return as_enum
|
|
|
|
return key
|
|
|
|
|
|
def has_tag(obj, tag):
|
|
return type(obj) is dict and tag in obj
|