marmots/tpers.py

276 lines
7.6 KiB
Python

import cPickle
import pdb
import traceback
def Decorator(dg):
def DecoratorNew(*rgarg, **mparg):
def CallDecorator(o):
return dg(o, *rgarg, **mparg) or o
return CallDecorator
return DecoratorNew
@Decorator
def Version(cls, vr):
cls._version = vr
def RenameFrom(stName, namespace):
def SetOldName(cls):
namespace[stName] = cls
return cls
return SetOldName
class TransientSetter(object):
def __init__(self, obj):
self.obj = obj
try:
self._fWriteOld = obj._fWriteToPersistent
except Exception:
self._fWriteOld = True
def __enter__(self):
self.obj._fWriteToPersistent = False
return self.obj
def __exit__(self, type, value, traceback):
self.obj._fWriteToPersistent = self._fWriteOld
@Version(1)
class TPrs(object):
def __init__(self, *rgarg, **mparg):
self._persistent = TPM()
self._fWriteToPersistent = True
self._versionCurr = self._version
self._fPersistent = True
self.InitPersistent(*rgarg, **mparg)
with self.SetTransiently():
self.InitTransient()
def InitPersistent(self, *rgarg, **mparg):
pass
def InitTransient(self):
pass
def SetTransiently(self):
return TransientSetter(self)
def MakeTransient(self, key, value):
try:
del self._persistent[key]
except Exception:
pass
with self.SetTransiently():
setattr(self, key, value)
def FPersist(self):
return self._fPersistent
def DontPersist(self):
self._fPersistent = False
def UpgradeFrom(self, versionOld):
pass
def __getattr__(self, key):
stPersistent = "no persistent yet"
if key != "_persistent":
try:
return self._persistent[key]
except Exception:
stPersistent = str(self._persistent)
raise AttributeError("Attribute '" + key + "' not found in object with type '" + type(self).__name__ + "':" + stPersistent + " __dict__:" + str(self.__dict__))
__obj_setattr = object.__setattr__
__obj_delattr = object.__delattr__
def __setattr__(self, key, value):
prop = getattr(self.__class__, key, None)
if isinstance(prop, property) and prop.fset:
prop.fset(self, value)
return
try:
if self._fWriteToPersistent or key in self._persistent:
self._persistent[key] = value
try:
self.__obj_delattr(key)
except AttributeError:
pass
return
except Exception: pass
self.__obj_setattr(key, value)
def __delattr__(self, key):
try:
del self._persistent[key]
except Exception:
self.__obj_delattr(key)
def __reduce__(self):
if self.FPersist():
return (NewObjWithClass, (type(self),), self._persistent)
else:
return (NewObjWithClass, (None,))
def __setstate__(self, state):
self._persistent = state
self._fWriteToPersistent = True
if self._versionCurr != self._version:
Odb.rgtprsToUpgrade.append(self)
Odb.rgtprsToInit.append(self)
def _Upgrade(self):
self.UpgradeFrom(self._versionCurr)
self._versionCurr = self._version
class Odb(object):
@staticmethod
def Save(tprs, fn):
with open(fn, "w") as fl:
cPickle.dump(tprs, fl)
@classmethod
def Load(cls, fn):
cls.rgtprsToUpgrade = []
cls.rgtprsToInit = []
try:
with open(fn, "r") as fl:
tprs = cPickle.load(fl)
except Exception as e:
print "error unpickling:", e
traceback.print_exc()
return None
for tprsToUpgrade in cls.rgtprsToUpgrade:
tprsToUpgrade._Upgrade()
for tprsToInit in cls.rgtprsToInit:
with tprsToInit.SetTransiently():
tprsToInit.InitTransient()
if len(cls.rgtprsToUpgrade) > 0:
fnUpgraded = fn + ".upgraded"
Odb.Save(tprs, fnUpgraded)
tprs = Odb.Load(fnUpgraded)
cls.rgtprsToUpgrade = None
cls.rgtprsToInit = None
return tprs
clsList = list
clsDict = dict
clsSet = set
clsTuple = tuple
def MkTransparent(value):
if type(value) == list:
return TPL(value)
elif type(value) == dict:
return TPM(value)
elif type(value) == set:
return TPS(value)
elif type(value) == tuple:
return TPT(value)
else:
return value
def RgTransparent(rg):
if rg == None: return []
return [MkTransparent(x) for x in rg]
def MpTransparent(mp):
if isinstance(mp, TPM): return mp
mpNew = {}
if mp != None:
for k,v in mp.iteritems():
mpNew[k] = MkTransparent(v)
return mpNew
def FPersist(obj):
return (not isinstance(obj, TPrs)) or obj.FPersist()
def MkPersistable(obj):
if FPersist(obj):
return obj
return None
def NewObjWithClass(cls):
if cls == None:
return None
return cls.__new__(cls)
class TPL(clsList):
__pl_setitem = clsList.__setitem__
__pl_setslice = clsList.__setslice__
__pl_iadd = clsList.__iadd__
__pl_append = clsList.append
__pl_insert = clsList.insert
__pl_extend = clsList.extend
def __init__(self, rg = None):
clsList.__init__(self, RgTransparent(rg))
def __setitem__(self, i, item):
return self.__pl_setitem(i, MkTransparent(item))
def __setslice__(self, i, j, other):
return self.__pl_setslice(i, j, RgTransparent(other))
def __iadd__(self, other):
return self.__pl_iadd(RgTransparent(other))
def append(self, item):
return self.__pl_append(MkTransparent(item))
def insert(self, i, item):
return self.__pl_insert(i, MkTransparent(item))
def extend(self, other):
return self.__pl_extend(RgTransparent(other))
def __reduce__(self):
return (MkTransparent, ([MkPersistable(x) for x in self],))
# Strip weak references rather than replacing them with None
class TPLS(TPL):
def __reduce__(self):
return (MkTransparent, ([x for x in self if FPersist(x)],))
class TPM(clsDict):
__pm_setitem = clsDict.__setitem__
__pm_update = clsDict.update
def __init__(self, *rgarg, **kwarg):
clsDict.__init__(self, MpTransparent(dict(*rgarg, **kwarg)))
def __setitem__(self, k, v):
return self.__pm_setitem(k, MkTransparent(v))
def update(self, other, **kwargs):
return self.__pm_update(MpTransparent(other), **MpTransparent(kwargs))
def __reduce__(self):
mp = {}
for k, v in self.iteritems():
if FPersist(k):
mp[k] = MkPersistable(v)
return (MkTransparent, (mp,))
class TPS(clsSet):
__ps_update = clsSet.update
__ps_ior = clsSet.__ior__
__ps_add = clsSet.add
def __init__(self, rg = None):
clsSet.__init__(self, RgTransparent(rg))
def update(self, *rgother):
return self.__ps_update(*RgTransparent(rgother))
def __ior__(self, other):
return self.__ps_ior(MkTransparent(other))
def add(self, elem):
return self.__ps_add(MkTransparent(elem))
def __reduce__(self):
return (MkTransparent, (set([x for x in self if FPersist(x)]),))
class TPT(clsTuple):
def __new__(cls, tup = None):
return clsTuple.__new__(cls, RgTransparent(tup))
def __reduce__(self):
return (MkTransparent, (tuple([MkPersistable(x) for x in self]),))