3
3
4
4
"""http://code.activestate.com/recipes/413838-memento-closure/"""
5
5
6
- import copy
6
+ from copy import copy , deepcopy
7
7
8
8
9
- def Memento (obj , deep = False ):
10
- state = ( copy . copy , copy . deepcopy )[ bool ( deep )] (obj .__dict__ )
9
+ def memento (obj , deep = False ):
10
+ state = copy ( obj . __dict__ ) if deep else deepcopy (obj .__dict__ )
11
11
12
- def Restore ():
12
+ def restore ():
13
13
obj .__dict__ .clear ()
14
14
obj .__dict__ .update (state )
15
- return Restore
16
15
16
+ return restore
17
17
18
- class Transaction :
19
18
20
- """A transaction guard. This is really just
21
- syntactic suggar arount a memento closure.
22
- """
19
+ class Transaction :
20
+ """A transaction guard.
21
+ This is, in fact, just syntactic sugar around a memento closure.
22
+ """
23
23
deep = False
24
+ states = []
24
25
25
26
def __init__ (self , * targets ):
26
27
self .targets = targets
27
- self .Commit ()
28
+ self .commit ()
28
29
29
- def Commit (self ):
30
- self .states = [Memento (target , self .deep ) for target in self .targets ]
30
+ def commit (self ):
31
+ self .states = [memento (target , self .deep ) for target in self .targets ]
31
32
32
- def Rollback (self ):
33
- for st in self .states :
34
- st ()
33
+ def rollback (self ):
34
+ for a_state in self .states :
35
+ a_state ()
35
36
36
37
37
- class transactional (object ):
38
-
38
+ class Transactional (object ):
39
39
"""Adds transactional semantics to methods. Methods decorated with
40
- @transactional will rollback to entry state upon exceptions.
40
+ @Transactional will rollback to entry- state upon exceptions.
41
41
"""
42
42
43
43
def __init__ (self , method ):
44
44
self .method = method
45
45
46
46
def __get__ (self , obj , T ):
47
47
def transaction (* args , ** kwargs ):
48
- state = Memento (obj )
48
+ state = memento (obj )
49
49
try :
50
50
return self .method (obj , * args , ** kwargs )
51
- except :
51
+ except Exception as e :
52
52
state ()
53
- raise
53
+ raise e
54
+
54
55
return transaction
55
56
56
57
57
58
class NumObj (object ):
58
-
59
59
def __init__ (self , value ):
60
60
self .value = value
61
61
62
62
def __repr__ (self ):
63
63
return '<%s: %r>' % (self .__class__ .__name__ , self .value )
64
64
65
- def Increment (self ):
65
+ def increment (self ):
66
66
self .value += 1
67
67
68
- @transactional
69
- def DoStuff (self ):
68
+ @Transactional
69
+ def do_stuff (self ):
70
70
self .value = '1111' # <- invalid value
71
- self .Increment () # <- will fail and rollback
71
+ self .increment () # <- will fail and rollback
72
72
73
73
74
74
if __name__ == '__main__' :
75
- n = NumObj (- 1 )
76
- print (n )
77
- t = Transaction (n )
75
+ num_obj = NumObj (- 1 )
76
+ print (num_obj )
77
+
78
+ a_transaction = Transaction (num_obj )
78
79
try :
79
80
for i in range (3 ):
80
- n .Increment ()
81
- print (n )
82
- t .Commit ()
83
- print ('-- commited' )
81
+ num_obj .increment ()
82
+ print (num_obj )
83
+ a_transaction .commit ()
84
+ print ('-- committed' )
85
+
84
86
for i in range (3 ):
85
- n . Increment ()
86
- print (n )
87
- n .value += 'x' # will fail
88
- print (n )
89
- except :
90
- t . Rollback ()
87
+ num_obj . increment ()
88
+ print (num_obj )
89
+ num_obj .value += 'x' # will fail
90
+ print (num_obj )
91
+ except Exception as e :
92
+ a_transaction . rollback ()
91
93
print ('-- rolled back' )
92
- print (n )
94
+ print (num_obj )
95
+
93
96
print ('-- now doing stuff ...' )
94
97
try :
95
- n . DoStuff ()
96
- except :
98
+ num_obj . do_stuff ()
99
+ except Exception as e :
97
100
print ('-> doing stuff failed!' )
98
101
import sys
99
102
import traceback
103
+
100
104
traceback .print_exc (file = sys .stdout )
101
- pass
102
- print ( n )
105
+ print ( num_obj )
106
+
103
107
104
108
### OUTPUT ###
105
109
# <NumObj: -1>
106
110
# <NumObj: 0>
107
111
# <NumObj: 1>
108
112
# <NumObj: 2>
109
- # -- commited
113
+ # -- committed
110
114
# <NumObj: 3>
111
115
# <NumObj: 4>
112
116
# <NumObj: 5>
@@ -115,13 +119,15 @@ def DoStuff(self):
115
119
# -- now doing stuff ...
116
120
# -> doing stuff failed!
117
121
# Traceback (most recent call last):
118
- # File "memento.py", line 91, in <module>
119
- # n.DoStuff()
120
- # File "memento.py", line 47, in transaction
122
+ # File "memento.py", line 97, in <module>
123
+ # num_obj.do_stuff()
124
+ # File "memento.py", line 52, in transaction
125
+ # raise e
126
+ # File "memento.py", line 49, in transaction
121
127
# return self.method(obj, *args, **kwargs)
122
- # File "memento.py", line 67 , in DoStuff
123
- # self.Increment () # <- will fail and rollback
124
- # File "memento.py", line 62 , in Increment
128
+ # File "memento.py", line 70 , in do_stuff
129
+ # self.increment () # <- will fail and rollback
130
+ # File "memento.py", line 65 , in increment
125
131
# self.value += 1
126
132
# TypeError: Can't convert 'int' object to str implicitly
127
133
# <NumObj: 2>
0 commit comments