1 # -*- test-case-name: twisted.test.test_persisted -*-
3 # Copyright (c) Twisted Matrix Laboratories.
4 # See LICENSE for details.
8 Utility classes for dealing with circular references.
13 from twisted.python import log, reflect
21 def addDependant(self, mutableObject, key):
22 assert not self.resolved
23 self.dependants.append( (mutableObject, key) )
27 def resolveDependants(self, newObject):
29 self.resolvedObject = newObject
30 for mut, key in self.dependants:
32 if isinstance(newObject, NotKnown):
33 newObject.addDependant(mut, key)
36 assert 0, "I am not to be used as a dictionary key."
40 class _Container(NotKnown):
42 Helper class to resolve circular references on container objects.
45 def __init__(self, l, containerType):
47 @param l: The list of object which may contain some not yet referenced
50 @param containerType: A type of container objects (e.g., C{tuple} or
53 NotKnown.__init__(self)
54 self.containerType = containerType
56 self.locs = range(len(l))
57 for idx in xrange(len(l)):
58 if not isinstance(l[idx], NotKnown):
61 l[idx].addDependant(self, idx)
63 self.resolveDependants(self.containerType(self.l))
66 def __setitem__(self, n, obj):
68 Change the value of one contained objects, and resolve references if
69 all objects have been referenced.
72 if not isinstance(obj, NotKnown):
75 self.resolveDependants(self.containerType(self.l))
79 class _Tuple(_Container):
81 Manage tuple containing circular references. Deprecated: use C{_Container}
85 def __init__(self, l):
87 @param l: The list of object which may contain some not yet referenced
90 _Container.__init__(self, l, tuple)
94 class _InstanceMethod(NotKnown):
95 def __init__(self, im_name, im_self, im_class):
96 NotKnown.__init__(self)
97 self.my_class = im_class
100 im_self.addDependant(self, 0)
102 def __call__(self, *args, **kw):
104 log.msg('instance method %s.%s' % (reflect.qual(self.my_class), self.name))
105 log.msg('being called with %r %r' % (args, kw))
106 traceback.print_stack(file=log.logfile)
109 def __setitem__(self, n, obj):
110 assert n == 0, "only zero index allowed"
111 if not isinstance(obj, NotKnown):
112 method = types.MethodType(self.my_class.__dict__[self.name],
114 self.resolveDependants(method)
116 class _DictKeyAndValue:
117 def __init__(self, dict):
119 def __setitem__(self, n, obj):
121 raise RuntimeError("DictKeyAndValue should only ever be called with 0 or 1")
126 if hasattr(self, "key") and hasattr(self, "value"):
127 self.dict[self.key] = self.value
130 class _Dereference(NotKnown):
131 def __init__(self, id):
132 NotKnown.__init__(self)
136 from twisted.internet.defer import Deferred
139 def catch(self, value):
142 class _Defer(Deferred, NotKnown):
144 Deferred.__init__(self)
145 NotKnown.__init__(self)
150 def __setitem__(self, n, obj):
152 raise RuntimeError('setitem should only be called once, setting %r to %r' % (n, obj))
157 def addDependant(self, dep, key):
158 # by the time I'm adding a dependant, I'm *not* adding any more
160 NotKnown.addDependant(self, dep, key)
163 self.resolveDependants(resovd)