PageRenderTime 416ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/junkyard/persistent.py

https://bitbucket.org/gsakkis/kitchen_sink
Python | 154 lines | 92 code | 36 blank | 26 comment | 26 complexity | ff1fd81314d76c9685ee7446bde4091f MD5 | raw file
  1. import sys,os
  2. _XXX_ = 1
  3. def make_persistent(binary=False, debug=False):
  4. # XXX: has to be imported here instead of global scope because during
  5. # finalization globals are set to None
  6. from cPickle import dump, load
  7. #--- Transaction ---------------------------------------------------------
  8. class Transaction(object):
  9. #__slots__ = '_changed', '_picklename'
  10. def __init__(self, *args, **kwds):
  11. if type(self) is Transaction:
  12. raise TypeError('Mixin class; cannot be instantiated directly')
  13. self._changed = True
  14. self._picklename = self.getPickleFilename(*args, **kwds)
  15. def __setattr__(self, attr, val):
  16. # Subclasses must call this first
  17. if attr not in ('_changed', '_picklename'): #Transaction.__slots__:
  18. self._changed = True
  19. #else:
  20. # parent = super(type(self),self).__setattr__
  21. # print "QW", parent
  22. # if parent is not Transaction:
  23. # parent = object
  24. # parent.__setattr__(self,attr,val)
  25. # if debug: print "Changed", attr
  26. def commit(self):
  27. if self._changed or not os.path.exists(self._picklename):
  28. picklefile = open(self._picklename,binary and 'wb' or 'w')
  29. try:
  30. dump(self, picklefile, binary)
  31. self._changed = False
  32. picklefile.close()
  33. if debug: print 'Saved', self
  34. except:
  35. self._changed = True
  36. picklefile.close()
  37. raise
  38. def rollback(self):
  39. if self._changed:
  40. if not os.path.exists(self._picklename):
  41. raise Transaction.Error("Cannot rollback before commit")
  42. new = load(open(self._picklename))
  43. assert type(new) is type(self)
  44. if debug: print 'Loaded', new
  45. if hasattr(new, '__getstate__'):
  46. state = new.__getstate__()
  47. else:
  48. state = new.__dict__
  49. if hasattr(self, '__setstate__'):
  50. self.__setstate__(state)
  51. else:
  52. self.__dict__.update(state)
  53. self._changed = False
  54. class Error(Exception):
  55. pass
  56. #--- PersistentMeta ------------------------------------------------------
  57. class PersistentMeta(type):
  58. def __new__(meta, clsname, bases, clsdict):
  59. assert Transaction not in bases
  60. if _XXX_:
  61. cls = type.__new__(meta, clsname, bases, clsdict)
  62. else:
  63. cls = type.__new__(meta, clsname, (Transaction,)+bases, clsdict)
  64. if not hasattr(cls, 'getPickleFilename'):
  65. raise TypeError('getPickleFilename() undefined in %s' % cls)
  66. old__init__ = cls.__init__
  67. def __init__(self, *args, **kwds):
  68. Transaction.__init__(self,*args, **kwds)
  69. if os.path.exists(self._picklename):
  70. self.rollback()
  71. else:
  72. old__init__(self, *args, **kwds)
  73. if _XXX_: clsdict['__init__'] = __init__
  74. else: cls.__init__ = __init__
  75. old__setattr__ = cls.__setattr__
  76. def __setattr__(self, attr, val):
  77. Transaction.__setattr__(self,attr,val)
  78. old__setattr__(self,attr,val)
  79. if _XXX_: clsdict['__setattr__'] = __setattr__
  80. else: cls.__setattr__ = __setattr__
  81. #old__del__ = getattr(cls, '__del__', None)
  82. #if old__del__ is not None:
  83. # def __del__(self):
  84. # try: old__del__()
  85. # except: pass
  86. # self.commit()
  87. # if _XXX_: clsdict['__del__'] = __del__
  88. # else: cls.__del__ = __del__
  89. #else:
  90. # if _XXX_: clsdict['__del__'] = Transaction.commit
  91. # else: cls.__del__ = Transaction.commit
  92. if _XXX_:
  93. cls = type.__new__(meta, clsname, (cls,Transaction), clsdict)
  94. return cls
  95. return PersistentMeta
  96. if __name__ == '__main__':
  97. class Test(object):
  98. __metaclass__ = make_persistent(debug=1)
  99. #__slots__ = ['id']
  100. def __init__(self, id):
  101. self.id = id
  102. import time; time.sleep(2)
  103. def getPickleFilename(self, id):
  104. return "%s.dat" % id
  105. class Foo(object):
  106. __slots__ = ['id']
  107. def __init__(self): self.id = 0
  108. def getPickleFilename(self, id):
  109. return "%s.bgw" % id
  110. class FooChild(Foo):
  111. def getPickleFilename(self, id):
  112. return self.__slots__, self.__dict__, self.id
  113. #return super(TestChild,self).getPickleFilename(id)
  114. t = Test(1)
  115. t.id += 1
  116. print t.id
  117. t.rollback();print t.id
  118. t.commit()