1 """
2 A generic callback mechanism.
3
4 Classes that wish to emit events inherit from L{Publisher}. Interested
5 clients call the L{Publisher.register} method on the object. The
6 publisher then calls L{Publisher.emit} to emit the event."""
7
8 import weakref
9
10
12 """ Invoked when a function call is performed on a destroyed method """
13 pass
14
15
17
18 """ A weak reference on a bound method """
19
21
22 self.f = f.im_func
23 self.c = weakref.ref(f.im_self)
24 return
25
26
28 o = self.c()
29
30 if o is None:
31 raise WeakError, 'Method called on dead object'
32
33 return apply (self.f, (o,) + arg)
34
36 try:
37 rf = fn.im_func
38 except AttributeError:
39 return False
40
41 return self.f is rf and self.c() is fn.im_self
42
43
45 """ A weak reference on an unbound method """
47 self.f = weakref.ref(f)
48 return
49
51 o = self.f()
52 if o is None :
53 raise WeakError , 'Function no longer exist'
54 return apply(o, arg)
55
58
59
68
69
71
72 """ Base class for objects that wish to emit signals to registered
73 clients."""
74
75
77 """ Intialize the publisher """
78
79 self.__observers = {}
80 return
81
82
83 - def emit(self, signal, *args):
84 """ Call this method to emit a signal. Registered client will
85 have their callbacks automatically invoked, with the specified
86 arguments """
87
88 try:
89 queue = self.__observers[signal]
90 except KeyError:
91 return
92
93 for data in queue[:]:
94 cb, bound = data
95 try:
96 apply(cb, args + bound)
97 except WeakError:
98 queue.remove(data)
99 continue
100 return
101
102
103 - def register(self, signal, callback, *args):
104
105 """ Clients interested in a given signal must register with
106 this method. The optional args are passed as the last
107 arguments (after the emit arguments) to the callback. """
108
109 queue = self.__observers.setdefault(signal, [])
110 queue.append((weakmethod(callback), args))
111 return
112
114 """ Stop notifying events for the specified signal/callback
115 pair."""
116
117 queue = self.__observers.get(signal,[])
118
119 for data in queue[:]:
120 cb, bound = data
121
122 if cb.same(callback):
123 queue.remove(data)
124
125 return
126