Package XPyLIB :: Module handler
[hide private]
[frames] | no frames]

Source Code for Module XPyLIB.handler

  1  #!/usr/bin/env python
 
  2  # -*- coding: utf-8 -*-
 
  3  #--------------------------------------------------------------------
 
  4  # Filname: handler.py
 
  5  # Author: Mazhugin Aleksey
 
  6  # Created: 2007/11/05
 
  7  # ID: $Id: XPyLIB.handler-pysrc.html 24 2008-12-01 17:51:12Z alex $
 
  8  # URL: $URL: file:///myfiles/svn_/XPyLIB/trunc/doc/html/XPyLIB.handler-pysrc.html $
 
  9  # Copyright: Copyright (c) 2007, Mazhugin Aleksey.
 
 10  # License: BSD
 
 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  # Importing
 
 47  import XPyLIB.dbg as dbg ##@ 
 48  
 
 49  
 
 50  # Start Implementation
 
 51  
 
52 -class HandlerError(Exception):
53 """ 54 Represent error or exception then calling handler. 55 """
56 - def __init__(self, exc):
57 """ 58 @param exc: Exception instance. 59 @type exc: Exception 60 """ 61 self.exc=exc
62
63 - def __str__(self):
64 """ 65 String convertation. 66 """ 67 return self.__class__.__name__ + '(): ' + str(self.exc)
68
69 -class Handler(object):
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
117 - def __init__(self, filter = None):
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
127 - def handler_add(self, *handlers):
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 # Add only unique. 141 self.__handler_hl.append(handler) 142 return len(self.__handler_hl)-1
143
144 - def handler_insert(self, index, *handlers):
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 # Add only unique. 159 self.__handler_hl.insert(i, handler) 160 i+=1 161 return i
162
163 - def handler_remove(self, *handlers):
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
173 - def handler_pop(self, index):
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
184 - def handler_has_handler(self, *handlers):
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
202 - def handler_getHandler(self, index):
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
213 - def __len__(self):
214 """ 215 Count handler-objects. 216 217 @return: Handler-objects count. 218 @rtype: int 219 """ 220 return len(self.__handler_hl)
221
222 - def __call__(self, *args, **kwds):
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 ##dbg.fwriteln('__call__ __handler_hl==', self.__handler_hl) ##@ 233 hl = self.__handler_hl 234 # Start filter. 235 c = False 236 if len(hl): 237 c = True # Continue condition. 238 if self.handler_filter: 239 try: 240 c = self.handler_filter("start", ("call", None), None) 241 except: 242 pass 243 ##if 244 ##if 245 # Handler filter. 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 ##if 255 if c: 256 try: 257 r=h(*args, **kwds) 258 except Exception, e: 259 r=HandlerError(e) 260 rez.append(r) 261 ##dbg.fwriteln('*** call ret ', r) ##@ 262 if self.handler_filter: 263 try: 264 c = self.handler_filter("post", ("call", None), h, r) 265 ##dbg.fwriteln('*** call filter ', c) ##@ 266 except Exception,e: 267 ##dbg.fwriteln('*** call filter EXC ', e) ##@ 268 pass 269 if not c: 270 ##dbg.fwriteln('BREAK') ##@ 271 break # Stop handler loop. 272 ##if 273 ##for 274 ##if c 275 # Stop filter. 276 if len(hl): 277 if self.handler_filter: 278 try: 279 self.handler_filter("stop", ("call", None), None) 280 except: 281 pass 282 ##if 283 ##if 284 285 return rez
286
287 - def __getattr__(self, name):
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 ##dbg.fwriteln('__getattr__.name=', name) ##@ 295 ##bg.fwriteln('__getattr__. __dict__=', self.__dict__) ##@ 296 r=Handler() 297 hl=self.__dict__['_Handler__handler_hl'] 298 hf=self.__dict__['handler_filter'] 299 c = False 300 # Start filter. 301 if len(hl): 302 c = True # Continue condition. 303 if hf: 304 try: 305 c = hf("start", ("get", None), None) 306 except: 307 pass 308 ##if 309 ##if 310 311 # Handler filter. 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 ##if 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 # Stop handler loop. 334 ##if 335 ##for 336 ##if c 337 338 # Stop filter. 339 if len(hl): 340 if hf: 341 try: 342 hf("stop", ("get", None), None) 343 except: 344 pass 345 ##if 346 ##if 347 348 return r
349
350 - def __setattr__(self,name,value):
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 ##dbg.fwriteln('__setattr__. name=', name) ##@ 363 # Set instance attributes. 364 if name in ('_Handler__handler_hl', 'handler_filter'): 365 object.__setattr__(self, name, value) 366 return 367 # Set handler-objects attributes. 368 rez=[] 369 hl = self.__handler_hl 370 c = False 371 # Start filter. 372 if len(hl): 373 c = True # Continue condition. 374 if self.handler_filter: 375 try: 376 c = self.handler_filter("start", ("get", None), None) 377 except: 378 pass 379 ##if 380 ##if 381 382 # Handler filter. 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 ##if 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 # Stop handler loop. 405 ##if 406 ##for 407 ##if c 408 409 # Stop filter. 410 if len(hl): 411 if self.handler_filter: 412 try: 413 self.handler_filter("stop", ("set", None), None) 414 except: 415 pass 416 ##if 417 ##if 418 419 return rez
420
421 - def __delattr__(self,name):
422 """ 423 Delete attrebute for all handler-objects. 424 """ 425 for h in self.__handler_hl: 426 try: 427 ##dbg.fwriteln('__del__: ', name) ##@ 428 delattr(h, name) 429 except Exception, e: 430 ##dbg.fwriteln('__del__ exception', e) ##@ 431 pass
432
433 - def __str__(self):
434 """ 435 Return informal string. 436 """ 437 ##dbg.fwriteln('__str__') ##@ 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
447 -class EventFilter(object):
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
458 - def __init__(self, StopIfTrue = True):
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 # Stop handler loop if have StopIfTrue equal result. 498 return False 499 # Continue handlers loop otherwise. 500 return True
501 502 503 # End Implemetation 504 505 #-DEBUG-START------------------------------------------------------------------- 506
507 -def _debug():
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 #-DEBUG-END--------------------------------------------------------------------- 525 526 if __name__=='__main__': 527 _debug() 528