1
2
3
4
5
6
7
8
9
10
11
12
13 """
14 General handlers implementation.
15
16 Implement operation with collection of objects (handler-objects) same as a single
17 object.
18
19 Quik start.
20 ===========
21
22 Program source::
23
24 def _debug():
25 import sys
26 h1=sys.stdout
27 h2=sys.stderr
28 ho=Handler()
29 ho.handler_add(h1,h2)
30 ho.write('Test handlerE{\}n')
31
32
33 In this programm you add two handler-objects (I{stdout} and I{stderr})
34 in B{Handler} I{ho}. Then you call function from this handler-objects.
35 Detail of function calling:
36 - In first you get new B{Handler} object with attributes I{write} used as
37 handler-object I{ho.write}.
38 - You do function call for each handler-object I{('Test handler\\n')}.
39 As rezult this action will be writen string I{'Test handler\\n'} into two stream.
40
41
42 @warning: For all index operation may return exception as L{list} object if
43 argument is wrong.
44 """
45
46
47 import XPyLIB.dbg as dbg
48
49
50
51
53 """
54 Represent error or exception then calling handler.
55 """
57 """
58 @param exc: Exception instance.
59 @type exc: Exception
60 """
61 self.exc=exc
62
64 """
65 String convertation.
66 """
67 return self.__class__.__name__ + '(): ' + str(self.exc)
68
70 """
71 Base handler class.
72
73 Workflow of handler processing is follow:
74 - Call C{filter(event="start", ("action", None), None)}.
75 - If returned C{True} enter handler loop (for each registered handler):
76 - Call C{filter("pre", ("call", None), handler, *args, **kwds)} for "call",
77 C{filter("pre", ("get", name), handler)} for "get",
78 C{filter("pre", ("set", name), handler, value)} for set.
79 - If returned C{True}:
80 - Call C{handler.action(*args, **kwds)} for "call" or getattr and
81 setattr for "get" and "set".
82 - Call C{filter("post", ("action", None), handler, result)}.
83 - Call C{filter("stop", ("action", None), None)}.
84
85 Pre processing filter functon must return C{True} for processing current handler and
86 C{False} for skip. Post processing filter must return C{True} for
87 continue processing remain handlers or C{False} for stop processing.
88
89
90 @ivar __handler_hl: Registered handlers list.
91 @type __handler_hl: list of handler instances
92
93 @ivar handler_filter: Filter function for handlers.
94 Called each time befor work with each handler.
95 Function must return C{True} for enable handler execution, or C{False} for
96 disable. Function I{B{C{ fun (event, action, handler, *args, **kwds) }}} where:
97 - B{event} - event type:
98 - "I{start}" - Initialization, befor start handlers loop.
99 - "I{pre}" - Pre handlers loop.
100 - "I{post}" - Post handlers loop.
101 - "I{stop}" - Deinitialization after handlers loop.
102 - B{action} - Tuple of (function, name) of method requested from handler.
103 - I{function} - "call", "get", "set" for calling, getattr and setattr.
104 - I{name} - name for attribute for "get" and "set", and None for "call".
105 - B{handler} - Handler instance.
106 - B{args} - Arguments passed to handler.
107 - B{kwds} - Keywords passed to handler.
108
109 Additional arguments:
110 - For "pre" + "call" - is function arguments.
111 - For "pre" + "set" arg[0] - is value to setup.
112 - For "post" arg[0] is result from handler.
113 @type handler_filter: function or None
114
115 """
116
118 """
119 @ivar handler_filter: Filter function for handlers.
120 @type handler_filter: function or None
121 """
122
123 self.__handler_hl = []
124
125 self.handler_filter = filter
126
128 """
129 Add handler-object.
130
131 @param handlers: Handler-objects for append.
132 Add only new handlers (unique for this list).
133 For not unique do nothing.
134 @type handlers: handler-objects instance
135 @return: Index of last added handler-object.
136 @rtype: int
137 """
138 for handler in handlers:
139 if handler not in self.__handler_hl:
140
141 self.__handler_hl.append(handler)
142 return len(self.__handler_hl)-1
143
145 """
146 Insert handler-object.
147
148 @param handlers: Handler-objects for inserting.
149 Insert only new handlers (unique for this list).
150 For not unique do nothing.
151 @type handlers: handler-objects instance
152 @return: Index of handler that point index befor insertion.
153 @rtype: int
154 """
155 i=index
156 for handler in handlers:
157 if handler not in self.__handler_hl:
158
159 self.__handler_hl.insert(i, handler)
160 i+=1
161 return i
162
164 """
165 Remove handler-objects.
166
167 @param handlers: Handler-objects for removing.
168 @type handlers: handler-object instance
169 """
170 for handler in handlers:
171 self.__handler_hl.remove(handler)
172
174 """
175 Remove and return handler-objects by index.
176
177 @param handlers: Handler-objects for removing.
178 @type handlers: handler-object instance.
179 @return: Poped handler.
180 @rtype: handler-object
181 """
182 return self.__handler_hl.pop(index)
183
185 """
186 Test handler-objects for exists.
187
188 @param handlers: Handler-objects for test.
189 @type handlers: handler-object instance
190 @return: List of handler-object's index if exist or B{-1} if not find.
191 @rtype: int
192 """
193 r=[]
194 for handler in handlers:
195 try:
196 i=self.__handler_hl.index(handler)
197 except ValueError:
198 i=-1
199 r.append(i)
200 return r
201
203 """
204 Get handler-object by index.
205
206 @param index: Handler's object index.
207 @type index: int
208 @return: Handler-bject.
209 @rtype: Handler-object instance
210 """
211 return self.__handler_hl[index]
212
214 """
215 Count handler-objects.
216
217 @return: Handler-objects count.
218 @rtype: int
219 """
220 return len(self.__handler_hl)
221
223 """
224 Execute call for each handler-object I{ho(*args, **kwds)}.
225
226 @return: List returned values from handler-objects. For error handler-objects
227 return L{HandlerError} instance instead object's rezult. Filtered
228 handlers is skiped from results. Error in filters is skiped and equivalent
229 True.
230 """
231 rez=[]
232
233 hl = self.__handler_hl
234
235 c = False
236 if len(hl):
237 c = True
238 if self.handler_filter:
239 try:
240 c = self.handler_filter("start", ("call", None), None)
241 except:
242 pass
243
244
245
246 if c:
247 for h in hl:
248 c = True
249 if self.handler_filter:
250 try:
251 c = self.handler_filter("pre", ("call", None), h, *args, **kwds)
252 except:
253 pass
254
255 if c:
256 try:
257 r=h(*args, **kwds)
258 except Exception, e:
259 r=HandlerError(e)
260 rez.append(r)
261
262 if self.handler_filter:
263 try:
264 c = self.handler_filter("post", ("call", None), h, r)
265
266 except Exception,e:
267
268 pass
269 if not c:
270
271 break
272
273
274
275
276 if len(hl):
277 if self.handler_filter:
278 try:
279 self.handler_filter("stop", ("call", None), None)
280 except:
281 pass
282
283
284
285 return rez
286
288 """
289 Get new handler of attribute's values from handler-objects.
290
291 @return: New of attribute's values from handler-objects.
292 @rtype: Handler
293 """
294
295
296 r=Handler()
297 hl=self.__dict__['_Handler__handler_hl']
298 hf=self.__dict__['handler_filter']
299 c = False
300
301 if len(hl):
302 c = True
303 if hf:
304 try:
305 c = hf("start", ("get", None), None)
306 except:
307 pass
308
309
310
311
312 if c:
313 for h in hl:
314 c = True
315 if hf:
316 try:
317 c = hf("pre", ("get", name), h)
318 except:
319 pass
320
321 if c:
322 try:
323 rr=getattr(h, name)
324 except AttributeError, e:
325 rr=HandlerError(e)
326 r.handler_add(rr)
327 if hf:
328 try:
329 c = hf("post", ("get", name), h, rr)
330 except:
331 pass
332 if not c:
333 break
334
335
336
337
338
339 if len(hl):
340 if hf:
341 try:
342 hf("stop", ("get", None), None)
343 except:
344 pass
345
346
347
348 return r
349
351 """
352 Set attrebute for all handler-objects.
353
354 @warning: For self may set only "__handler_hl" attribute.
355 All other attributes try set to handler-objects.
356
357 @return: List of rezults for handler-objects:
358 None if no error, or Exception instance
359 if error occur.
360 @rtype: list
361 """
362
363
364 if name in ('_Handler__handler_hl', 'handler_filter'):
365 object.__setattr__(self, name, value)
366 return
367
368 rez=[]
369 hl = self.__handler_hl
370 c = False
371
372 if len(hl):
373 c = True
374 if self.handler_filter:
375 try:
376 c = self.handler_filter("start", ("get", None), None)
377 except:
378 pass
379
380
381
382
383 if c:
384 for h in hl:
385 c = True
386 if self.handler_filter:
387 try:
388 c = self.handler_filter("pre", ("set", name), h, value)
389 except:
390 pass
391
392 if c:
393 try:
394 r=setattr(h, name, value)
395 except Exception, e:
396 r=HandlerError(e)
397 rez.append(r)
398 if self.handler_filter:
399 try:
400 c = self.handler_filter("post", ("set", name), h, r)
401 except:
402 pass
403 if not c:
404 break
405
406
407
408
409
410 if len(hl):
411 if self.handler_filter:
412 try:
413 self.handler_filter("stop", ("set", None), None)
414 except:
415 pass
416
417
418
419 return rez
420
422 """
423 Delete attrebute for all handler-objects.
424 """
425 for h in self.__handler_hl:
426 try:
427
428 delattr(h, name)
429 except Exception, e:
430
431 pass
432
434 """
435 Return informal string.
436 """
437
438 s='Handler instance: ['
439 for h in self.__handler_hl:
440 s+=str(h)+', '
441 if self.__handler_hl:
442 s=s[:-2]
443 s+=']'
444 return s
445
446
448 """
449 Event filter for L{Handler}.
450
451 Emulate event handler (with L{Handler}). When has event and it buble from
452 one object to another. If any object is return specified result
453 (True for example) then bubling is stoped.
454 Filter is filtered only "call" action.
455 See L{EventFilter.__init__} and L{EventFilter.__call__}.
456 """
457
459 """
460 @param StopIfTrue: Initialize L{stopIfTrue} variable.
461 @type StopIfTrue: bool = True
462
463 @ivar stopIfTrue: StopIfTrue: Stop handler loop condition - if value this parameter
464 is equal result from handler then handler iterations will be stoped,
465 otherwise continue. Filter only "call" action.
466 @type stopIfTrue: bool
467 """
468
469 self.stopIfTrue = StopIfTrue
470
471 - def __call__(self, event, action, handler, *args, **kwds):
472 """
473 Callable function for handler filter.
474
475 See L{Handler.filter}.
476
477 @param event: Event type. May be "start", "pre", "post", "stop" events.
478 @type event: str
479 @param action: Tuple of action - ("action", "name"). action may be
480 "call", "get", "set". name - is a requested attribute name for
481 "get" and "set" and None for "call".
482 @type action: tuple
483 @param handler: Handler instance (not Handler class) for which called
484 filter.
485 @type handler: object
486 @param args: Additional arguments.
487 - For "pre" + "call" - is function arguments.
488 - For "pre" + "set" arg[0] - is value to setup.
489 - For "post" arg[0] is result from handler.
490 @param kwds: Additional keywords. Applied only for "call" action.
491 @return: True for continue loop or False otherwise.
492 @rtype: bool
493 """
494
495 if event == "post" and action[0] == "call":
496 if not (bool(args[0]) ^ self.stopIfTrue):
497
498 return False
499
500 return True
501
502
503
504
505
506
508 """
509 """
510 import sys
511 h1=sys.stdout
512 h2=sys.stderr
513 ho=Handler()
514 ho.handler_add(h1,h2)
515 ho.write('Test handler\n')
516 print str(ho)
517 print str(ho.__class__)
518 print str(ho.__dict__)
519
520
521 del sys
522 pass
523
524
525
526 if __name__=='__main__':
527 _debug()
528