python-objectbroker/objectbroker/Serializer.py

113 lines
3.2 KiB
Python

import weakref
import collections
from objectbroker.Persistence import Persistence,NoPersistence
class Serializer:
"""Base class for object serialization with support for persistence"""
def __init__(self, objStore, objCache = weakref.WeakValueDictionary() ):
self.__objStore = objStore
self.__objCache = objCache
def serialize(self, o):
slist = {}
state = self.objectToState( o, slist )
self.__objStore.save(state, slist)
def unserialize(self, pid):
o = self.objectFromCache( pid )
if o is None:
state = self.__objStore.load( pid )
o = self.stateToObject( state )
return o
def objectToState(self, o, states = {} ):
"""Create a state dict for an object <o>.
Returns the state dict.
After method returns, <states> will contain entries for all referenced persistent objects."""
if not isinstance(o, Persistence):
raise TypeError("needs to be based on Persistence class to be used as persistent object")
if Persistence._persistence_id( o ) in states:
return states[ Persistence._persistence_id( o ) ]
state = {}
state["pid"] = Persistence._persistence_id( o )
state["module"] = o.__class__.__module__
state["class"] = o.__class__.__name__
state["fields"] = {}
state["pfields"] = {}
nopersistence = self.collectClassAttribute(o.__class__,"NOPERSIST")
persistnone = self.collectClassAttribute(o.__class__,"PERSISTNONE")
states[ state["pid"] ] = state
d = object.__getattribute__(o, "__dict__")
for n in d.keys():
a = getattr( o, n )
if (not isinstance( a, collections.Callable)) or isinstance( a, object ):
if (isinstance( a, NoPersistence)) or (n in nopersistence):
state["fields"][n] = a
elif n in persistnone:
state["fields"][n] = None
elif (isinstance( a, Persistence)):
state["pfields"][n] = self.objectToState( a, states )["pid"]
else:
state["fields"][n] = a
return state
def stateToObject(self, state):
"""Returns an object that is constructed of the given state.
If the cache already holds a reference to an object with the same persistence id,
this reference is returned without any alternation of the object."""
o = self.objFromCache( state["pid"] )
if not o is None:
return o
m = __import__(state["module"],fromlist=[state["class"]])
cls = getattr(m, state["class"] )
o = cls.__new__(cls)
objToCache( o, state["pid"] )
for n in state["fields"]:
setattr( o, n, state["fields"][n] )
for n in state["pfields"]:
setattr( o, n, self.stateToObject( state["pfields"][n] ))
return o
def objFromCache(self, pid):
if not self.__objCache is None:
if pid in self.__objCache:
return self.__objCache[ pid ]
return None
def objToCache(self, o, pid = None):
if pid is None:
pid = Persistence._persistence_id( o )
if not self.__objCache is None:
if not pid in self.__objCache:
self.__objCache[ pid ] = o
def collectClassAttribute(self, c, name, default = set() ):
collection = default
classes = (self.__class__,) + self.__class__.__bases__
for clazz in classes:
if hasattr(clazz, name):
if isinstance( collection, dict ):
collection.update( getattr( clazz, name ) )
else:
collection = collection + getattr( clazz, name )
return collection