-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathevent.py
267 lines (200 loc) · 7.83 KB
/
event.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#!/usr/bin/env python
"""
Event handling.
Basic design of Event and EventProxy is derived from the code written by:
Masaaki Shibata <[email protected]> http://www.emptypage.jp/
The original code is in the public domain. The document which describes the
original code is located at:
http://www.emptypage.jp/notes/pyevent.html
"""
from builtins import object
class Event(object):
"""
Event.
"""
def __init__(self):
"""
Create an event.
"""
self.__slots__ = ['__doc__']
def __get__(self, obj, objtype=None):
if obj is None:
return self
return EventProxy(self, obj)
def __set__(self, obj, value):
pass
class EventProxy(object):
"""
Event proxy, administering event handlers and propagate events.
"""
def __init__(self, event, sender):
"""
Create an event proxy.
"""
self.__slots__ = ['_event', '_sender']
self._event = event
self._sender = sender
def _get_handlers(self):
if hasattr(self._sender, '__eventhandler__'):
eventhandler = self._sender.__eventhandler__
else:
eventhandler = self._sender.__eventhandler__ = {}
return eventhandler.setdefault(self._event, [])
def add(self, handler):
"""
Add a new event handler.
:param handler: event handler or callable object
This method adds *handler* to the registered event handler list.
Registered event handlers will be called in the order they were
registered. If *handler* is not an instance of :class:`EventHandler`,
a new :class:`EventHandler` is created with *handler*.
If you do not have your customized event handler, it is encouraged that
you use '+=' operator or '<<=' operator instead. See :meth:`__iadd__`
or :meth:`__lshift__`.
"""
if isinstance(handler, EventHandler):
self._get_handlers().append(handler)
else:
self._get_handlers().append(EventHandler(handler))
return self
def remove(self, handler):
"""
Remove the event handler.
:param handler: event handler or callable object
This method removes *handler* from the registered event handler list.
*handler* can be either an instance of :class:`EventHandler` or a
callable object. If more than one handler identical to *handler* is
registered, they are all removed.
You can remove a handler also by using '-=' operator::
foo.clicked -= handler
"""
handlers = self._get_handlers()
if isinstance(handler, EventHandler):
handlers[:] = [h for h in handlers if h is not handler]
else:
# Note that bound method objects are not the same instances;
# Do not use 'h.callable is not handler'
handlers[:] = [h for h in handlers if h.callable != handler]
return self
def fire(self, *args, **kwargs):
"""
Fire the event and call the registered event handlers.
:param args: positional arguments passed to event handlers
:param kwargs: keyword arguments passed to event handlers
This method calls all the registered event handlers. Registered event
handlers will be called in the order they were registered.
The value of *args* and *kwargs* will propagate to each registered
handler.
You can call the event itself instead of this method::
foo.clicked(some_parameter, another_parameter)
"""
handlers = self._get_handlers()
called_handlers = (
handler(self._sender, *args, **kwargs) for handler in handlers)
handlers[:] = [handler for handler in called_handlers if handler]
def __iadd__(self, callable):
"""
Add a new event handler.
:param callable: callable
This method creates an :class:`EventHandler` with *callable* and adds
it to the registered event handler list. Registered event handlers
will be called in the order they were registered.
Event handlers can be either a function or a method. It has to have
at least one parameter *sender*, so handlers will take a form of::
def function(sender):
# some code to handle the event....
pass
Or::
class Observer(object):
def method(self, sender):
# some code to handle the event....
pass
The value of *sender* will be the owner; that is, the object to which
the event belongs.
If the description of an event says that it has some parameters, event
handlers also should have parameters to receive arguments passed for
raising the event. For example, if an event has two parameters *foo*
and *bar* in this order, an event handler of it should be::
def function(sender, foo, bar):
# you can do some task using foo and bar....
pass
Or::
class Observer(object):
def method(self, sender, foo, bar):
# you can do some task using foo and bar....
pass
You can add a handler also by using '+=' operator::
foo.clicked += function
foo.clicked += Observer().method
If you want to add a handler which runs only once, use '<<=' operator
instead::
foo.clicked <<= function
foo.clicked <<= Observer().method
"""
return self.add(EventHandler(callable))
def __ilshift__(self, callable):
"""
Add a new run-once event handler.
:param callable: callable
This method creates a :class:`RunOnceEventHandler`, not an
:class:`EventHandler`, with *callable* and adds it to the registered
event handler list. For the rest part this method is the same as
:meth:`__add__`. See :meth:`__add__` for details.
You can add a run-once handler also by '<<=' operator::
foo.clicked <<= function
foo.clicked <<= Observer().method
If you add a regular handler which is called every time until being
removed, use '+=' operator instead::
foo.clicked += function
foo.clicked += Observer().method
"""
return self.add(RunOnceEventHandler(callable))
__isub__ = remove
__call__ = fire
class EventHandler(object):
"""
Event handler.
:param callable: callable object
"""
def __init__(self, callable):
"""
Create an event handler.
"""
self._callable = callable
@property
def callable(self):
"""
The callable object.
"""
return self._callable
def __call__(self, sender, *args, **kwargs):
"""
Call the callable.
:param sender: sender of the event
:param args: positional arguments passed to event handlers
:param kwargs: keyword arguments passed to event handlers
"""
self._callable(sender, *args, **kwargs)
return self
class RunOnceEventHandler(EventHandler):
"""
*Run-Once* Event handler, which is called only once.
:param callable: callable object
"""
def __init__(self, callable):
"""
Create a run-once event handler.
"""
super(RunOnceEventHandler, self).__init__(callable)
def __call__(self, sender, *args, **kwargs):
"""
Call the callable object.
:param sender: sender of the event
:param args: positional arguments passed to event handlers
:param kwargs: keyword arguments passed to event handlers
"""
self._callable(sender, *args, **kwargs)
return None
if __name__ == '__main__':
import event_test
event_test.main()