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