| 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 |