OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_persisted -*- | |
2 | |
3 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
4 # See LICENSE for details. | |
5 | |
6 | |
7 """ | |
8 Utility classes for dealing with circular references. | |
9 """ | |
10 | |
11 from twisted.python import log, reflect | |
12 | |
13 try: | |
14 from new import instancemethod | |
15 except: | |
16 from org.python.core import PyMethod | |
17 instancemethod = PyMethod | |
18 | |
19 | |
20 class NotKnown: | |
21 def __init__(self): | |
22 self.dependants = [] | |
23 self.resolved = 0 | |
24 | |
25 def addDependant(self, mutableObject, key): | |
26 assert not self.resolved | |
27 self.dependants.append( (mutableObject, key) ) | |
28 | |
29 resolvedObject = None | |
30 | |
31 def resolveDependants(self, newObject): | |
32 self.resolved = 1 | |
33 self.resolvedObject = newObject | |
34 for mut, key in self.dependants: | |
35 mut[key] = newObject | |
36 if isinstance(newObject, NotKnown): | |
37 newObject.addDependant(mut, key) | |
38 | |
39 def __hash__(self): | |
40 assert 0, "I am not to be used as a dictionary key." | |
41 | |
42 | |
43 | |
44 class _Container(NotKnown): | |
45 """ | |
46 Helper class to resolve circular references on container objects. | |
47 """ | |
48 | |
49 def __init__(self, l, containerType): | |
50 """ | |
51 @param l: The list of object which may contain some not yet referenced | |
52 objects. | |
53 | |
54 @param containerType: A type of container objects (e.g., C{tuple} or | |
55 C{set}). | |
56 """ | |
57 NotKnown.__init__(self) | |
58 self.containerType = containerType | |
59 self.l = l | |
60 self.locs = range(len(l)) | |
61 for idx in xrange(len(l)): | |
62 if not isinstance(l[idx], NotKnown): | |
63 self.locs.remove(idx) | |
64 else: | |
65 l[idx].addDependant(self, idx) | |
66 if not self.locs: | |
67 self.resolveDependants(self.containerType(self.l)) | |
68 | |
69 | |
70 def __setitem__(self, n, obj): | |
71 """ | |
72 Change the value of one contained objects, and resolve references if | |
73 all objects have been referenced. | |
74 """ | |
75 self.l[n] = obj | |
76 if not isinstance(obj, NotKnown): | |
77 self.locs.remove(n) | |
78 if not self.locs: | |
79 self.resolveDependants(self.containerType(self.l)) | |
80 | |
81 | |
82 | |
83 class _Tuple(_Container): | |
84 """ | |
85 Manage tuple containing circular references. Deprecated: use C{_Container} | |
86 instead. | |
87 """ | |
88 | |
89 def __init__(self, l): | |
90 """ | |
91 @param l: The list of object which may contain some not yet referenced | |
92 objects. | |
93 """ | |
94 _Container.__init__(self, l, tuple) | |
95 | |
96 | |
97 | |
98 class _InstanceMethod(NotKnown): | |
99 def __init__(self, im_name, im_self, im_class): | |
100 NotKnown.__init__(self) | |
101 self.my_class = im_class | |
102 self.name = im_name | |
103 # im_self _must_ be a | |
104 im_self.addDependant(self, 0) | |
105 | |
106 def __call__(self, *args, **kw): | |
107 import traceback | |
108 log.msg('instance method %s.%s' % (reflect.qual(self.my_class), self.nam
e)) | |
109 log.msg('being called with %r %r' % (args, kw)) | |
110 traceback.print_stack(file=log.logfile) | |
111 assert 0 | |
112 | |
113 def __setitem__(self, n, obj): | |
114 assert n == 0, "only zero index allowed" | |
115 if not isinstance(obj, NotKnown): | |
116 self.resolveDependants(instancemethod(self.my_class.__dict__[self.na
me], | |
117 obj, | |
118 self.my_class)) | |
119 | |
120 class _DictKeyAndValue: | |
121 def __init__(self, dict): | |
122 self.dict = dict | |
123 def __setitem__(self, n, obj): | |
124 if n not in (1, 0): | |
125 raise RuntimeError("DictKeyAndValue should only ever be called with
0 or 1") | |
126 if n: # value | |
127 self.value = obj | |
128 else: | |
129 self.key = obj | |
130 if hasattr(self, "key") and hasattr(self, "value"): | |
131 self.dict[self.key] = self.value | |
132 | |
133 | |
134 class _Dereference(NotKnown): | |
135 def __init__(self, id): | |
136 NotKnown.__init__(self) | |
137 self.id = id | |
138 | |
139 | |
140 from twisted.internet.defer import Deferred | |
141 | |
142 class _Catcher: | |
143 def catch(self, value): | |
144 self.value = value | |
145 | |
146 class _Defer(Deferred, NotKnown): | |
147 def __init__(self): | |
148 Deferred.__init__(self) | |
149 NotKnown.__init__(self) | |
150 self.pause() | |
151 | |
152 wasset = 0 | |
153 | |
154 def __setitem__(self, n, obj): | |
155 if self.wasset: | |
156 raise RuntimeError('setitem should only be called once, setting %r t
o %r' % (n, obj)) | |
157 else: | |
158 self.wasset = 1 | |
159 self.callback(obj) | |
160 | |
161 def addDependant(self, dep, key): | |
162 # by the time I'm adding a dependant, I'm *not* adding any more | |
163 # callbacks | |
164 NotKnown.addDependant(self, dep, key) | |
165 self.unpause() | |
166 resovd = self.result | |
167 self.resolveDependants(resovd) | |
OLD | NEW |