1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- """code.activestate.com/recipes/413838-memento-closure/"""
- import copy
- def Memento(obj, deep=False):
- state = (copy.copy, copy.deepcopy)[bool(deep)](obj.__dict__)
- def Restore():
- obj.__dict__.clear()
- obj.__dict__.update(state)
- return Restore
- class Transaction:
- """A transaction guard. This is really just
- syntactic suggar arount a memento closure.
- """
- deep = False
- def __init__(self, *targets):
- self.targets = targets
- self.Commit()
- def Commit(self):
- self.states = [Memento(target, self.deep) for target in self.targets]
- def Rollback(self):
- for st in self.states:
- st()
- class transactional(object):
- """Adds transactional semantics to methods. Methods decorated with
- @transactional will rollback to entry state upon exceptions.
- """
- def __init__(self, method):
- self.method = method
- def __get__(self, obj, T):
- def transaction(*args, **kwargs):
- state = Memento(obj)
- try:
- return self.method(obj, *args, **kwargs)
- except:
- state()
- raise
- return transaction
- class NumObj(object):
- def __init__(self, value):
- self.value = value
- def __repr__(self):
- return '<%s: %r>' % (self.__class__.__name__, self.value)
- def Increment(self):
- self.value += 1
- @transactional
- def DoStuff(self):
- self.value = '1111' # <- invalid value
- self.Increment() # <- will fail and rollback
- if __name__ == '__main__':
- n = NumObj(-1)
- print(n)
- t = Transaction(n)
- try:
- for i in range(3):
- n.Increment()
- print(n)
- t.Commit()
- print('-- commited')
- for i in range(3):
- n.Increment()
- print(n)
- n.value += 'x' # will fail
- print(n)
- except:
- t.Rollback()
- print('-- rolled back')
- print(n)
- print('-- now doing stuff ...')
- try:
- n.DoStuff()
- except:
- print('-> doing stuff failed!')
- import traceback
- traceback.print_exc(0)
- pass
- print(n)
|