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

Source Code for Module XPyLIB.dbg

  1  #!/usr/bin/env python
 
  2  # -*- coding: utf-8 -*-
 
  3  #--------------------------------------------------------------------
 
  4  # Author: Mazhugin Aleksey
 
  5  # Created: 2007/10/01
 
  6  # ID: $Id: XPyLIB.dbg-pysrc.html 24 2008-12-01 17:51:12Z alex $
 
  7  # URL: $URL: file:///myfiles/svn_/XPyLIB/trunc/doc/html/XPyLIB.dbg-pysrc.html $
 
  8  # Copyright: Copyright (c) 2007, Mazhugin Aleksey
 
  9  # License: BSD
 
 10  #--------------------------------------------------------------------
 
 11  
 
 12  """
 
 13  Simple debug module.
 
 14  
 
 15  Used for fast debugging. You may set debug output into two different
 
 16  streams: L{outstream} and L{fstream}. Preferred assignment for streams is:
 
 17      - outstream - any console output (by default I{stderr}.
 
 18      - fstream - any file output (default is "dbg.log" file into "~/.XPyLIB/logs"),
 
 19          where "~" is a user home directory. A dir mode is 0660. If path is
 
 20          not exist then created automaticaly.
 
 21  Function for file output starts with B{f} letter.
 
 22  Initialization of streams (open file) is doing only if calling writing
 
 23  function and stream is not initialized. Before start debug output you can
 
 24  initialize streams you own objects which support B{write} method.
 
 25  Then program exit autocalling L{shutdown} function which close L{fstream}
 
 26  if it was opened. If in program no debug output then streams are not
 
 27  created and file are not opened.
 
 28  
 
 29  Also you may use indentation level by calling L{lvlup}(), L{lvldown}() and
 
 30  decorators L{level}, L{wlevel} and L{fwlevel}.
 
 31  Indentation level used only in next functions: L{fwriteln}()
 
 32  and L{writeln}(). For tune indentation use L{levelbodychar},
 
 33  L{levelendchar}, L{levelwidth}.
 
 34  
 
 35  
 
 36  Debug output example, see L{_debug})::
 
 37      
 
 38      *** DEBUG START ***
 
 39      
 
 40      >456
 
 41      ..>tst1:test
 
 42      >CALL tst2()
 
 43      ..>tst2 start
 
 44      ..>tst1:from tst2
 
 45      ..>CALL tst3()
 
 46      ....>tst3
 
 47      ..>RET from tst3()
 
 48      ..>tst2 end
 
 49      >RET from tst2()
 
 50      >CALL tst2()
 
 51      ..>tst2 start
 
 52      ..>tst1:from tst2
 
 53      ..>CALL tst3()
 
 54      ....>tst3
 
 55      ..>RET from tst3()
 
 56      ..>tst2 end
 
 57      >RET from tst2()
 
 58      
 
 59      
 
 60      *** DEBUG END ***
 
 61  
 
 62  
 
 63  @var outstream: Output stream, default is I{sys.stdout}.
 
 64  @type outstream: stream(file-like object).
 
 65  
 
 66  @var fstream: Output stream, default is "dbg.log" file into "~/.XPyLIB/logs"
 
 67      directory or sys.stderr if file is not available. This stream autoclosed
 
 68      then exit from application (used atexit module).
 
 69  @type fstream: stream(file-like object).
 
 70  @var levelbodychar: Character that fill indentation spaces.
 
 71  @type levelbodychar: str
 
 72  @var levelendchar: Character that insert before string output but after
 
 73      level indentation.
 
 74  @type levelendchar: str
 
 75  @var levelwidth: Number of indentation characters in one indentation level.
 
 76  @type levelwidth: int
 
 77  @var levelerr: Error message then level indentation is invalid thrn return from
 
 78      wrapped function.
 
 79  @type levelerr: int
 
 80  @var _level: Indentation level.
 
 81  @type _level: int
 
 82  
 
 83  @var descfuncall: Function call description.
 
 84  @type descfuncall: str
 
 85  @var descfunret: Function return description.
 
 86  @type descfunret: str
 
 87  
 
 88  @var desceval: String that prepend to eval expression.
 
 89  @type desceval: str
 
 90  @var descevalrez: String that prepend to eval resultat.
 
 91  @type descevalrez: str
 
 92  @var descevalexc: String that prepend to eval exception.
 
 93  @type descevalexc: str
 
 94  @var descevalln: String that added at end of eval output.
 
 95  @type descevalln: str
 
 96  """ 
 97  
 
 98  import sys 
 99  import atexit 
100  import os 
101  from functools import wraps 
102  
 
103  outstream = None 
104  fstream = None 
105  
 
106  levelbodychar = '.' 
107  levelendchar = '>' 
108  levelwidth = 2 
109  levelerr = '*** LEVEL ERROR = ' 
110  descfuncall = 'CALL ' 
111  descfunret = 'RET from ' 
112  desceval = 'EVAL: ' 
113  descevalrez = '  ER=' 
114  descevalexc = '  EXCEPTION:' 
115  descevalln = ' ' 
116  
 
117  _level = 0 
118  
 
119 -def lvlup():
120 """ 121 Increase indentation level. 122 """ 123 global _level 124 _level+=1
125
126 -def lvldown():
127 """ 128 Decrease indentation level. 129 """ 130 global _level 131 _level-=1 132 if _level < 0: 133 _level = 0
134
135 -def lvlreset():
136 """ 137 Reset indentation level to "0". 138 """ 139 global _level 140 _level = 0
141
142 -def level(fun):
143 """ 144 Auto level decorator for functions. 145 146 Call L{lvlup}() befor function call and L{lvldown}() after 147 wrapped function return. 148 @param fun: Wrapped function. 149 @type fun: func 150 """ 151 @wraps(fun) 152 def wrapper(*args, **kwds): 153 global _level 154 l=_level 155 lvlup() 156 exc=False 157 try: 158 r = fun(*args, **kwds) 159 except Exception, e: 160 exc=e 161 ##lvldown() 162 _level=l # Defense from error 163 if exc: 164 raise exc 165 return r
166 return wrapper 167
168 -def fwlevel(fun):
169 """ 170 Auto level and name decorator for functions. 171 172 Write first 'Call "fun.__name__"' using L{fwriteln}(). 173 Also as L{level}(). 174 If level error tested then write '*** DBG LEVEL ERROR = different' 175 where 'different' is level different. 176 Write last 'Return from "fun.__name__"' using L{fwriteln}(). 177 @param fun: Wrapped function. 178 @type fun: func 179 """ 180 @wraps(fun) 181 def wrapper(*args, **kwds): 182 global _level 183 fwriteln(descfuncall, fun.__name__, '()') 184 l=_level 185 lvlup() 186 exc=False 187 try: 188 r = fun(*args, **kwds) 189 except Exception, e: 190 exc=e 191 lvldown() 192 if l != _level: 193 d=_level-l 194 _level=l 195 fwriteln(levelerr, d) 196 fwriteln(descfunret, fun.__name__, '()') 197 if exc: 198 raise exc 199 return r
200 return wrapper 201
202 -def wlevel(fun):
203 """ 204 Auto level and name decorator for functions. 205 206 Write first 'Call "fun.__name__"' using L{writeln}(). 207 Also as L{level}(). 208 If level error tested then write '*** DBG LEVEL ERROR = different' 209 where 'different' is level different. 210 Write last 'Return from "fun.__name__"' using L{writeln}(). 211 @param fun: Wrapped function. 212 @type fun: func 213 """ 214 @wraps(fun) 215 def wrapper(*args, **kwds): 216 global _level 217 writeln(descfuncall, fun.__name__, '()') 218 l=_level 219 lvlup() 220 exc=False 221 try: 222 r = fun(*args, **kwds) 223 except Exception, e: 224 exc=e 225 lvldown() 226 if l != _level: 227 d=_level-l 228 _level=l 229 fwriteln(levelerr, d) 230 writeln(descfunret, fun.__name__, '()') 231 if exc: 232 raise exc 233 return r
234 return wrapper 235
236 -def shutdown():
237 """ 238 Close opened file stream L{fstream}. 239 """ 240 global fstream 241 global outstream 242 if fstream: 243 fstream.write('\n\n*** DEBUG END ***') 244 if fstream is not sys.stderr: 245 fstream.close() 246 fstream=None 247 if outstream: 248 outstream.write('\n\n*** DEBUG END ***')
249
250 -def outstream_init():
251 """ 252 Initialize output stream. 253 """ 254 global outstream 255 if not outstream: 256 outstream = sys.stderr 257 outstream.write('*** DEBUG START ***\n\n')
258
259 -def fstream_init():
260 """ 261 Initialize file output stream. 262 263 Default is "dbg.log" file into "~/.XPyLIB/logs" 264 directory or sys.stderr if file is not available. 265 Where "~" is a user home directory. Path autocreate if need. 266 Mode of dirs is 0660. 267 """ 268 global fstream 269 if not fstream: 270 try: 271 p=os.path.expanduser("~") 272 p=os.path.join(p, ".xpylib", "logs") 273 if not os.path.exists(p): 274 os.makedirs(p,0660) ## rw-rw---- 275 p=os.path.join(p,'dbg.log') 276 fstream=open(p,'w',0) 277 278 ## p=os.path.dirname(os.path.abspath(__file__)) 279 ## if p.endswith('.zip'): 280 ## p=os.path.dirname(p) 281 ## p=os.path.join(os.path.dirname(p), 'logs','dbg.log') 282 ## fstream=open(p,'w',0) 283 284 except Exception, e: 285 fstream=sys.stderr 286 fstream.write('Can\'t open file for debug logging.\nerror:' + \ 287 str(e) + '\n\n') 288 fstream.write('*** DEBUG START ***\n\n')
289 290
291 -def fwrite(*arg):
292 """ 293 Write concatenated arguments into outstream. 294 295 @param arg: Object to output. All objects convert to string I{str()} function. 296 @type arg: *object 297 @return: None. 298 @rtype: None 299 """ 300 fstream_init() 301 fstream.write( reduce(lambda a, b: a + str(b), arg, '') )
302 303
304 -def write(*arg):
305 """ 306 Write concatenated arguments into outstream. 307 308 @param arg: Object to output. All objects convert to string I{str()} function. 309 @type arg: *object 310 @return: None. 311 @rtype: None 312 """ 313 outstream_init() 314 outstream.write( reduce(lambda a, b: a + str(b), arg, '') )
315
316 -def _writeln(fun, *arg):
317 """ 318 Write concatenated arguments into outstream and append new line ('\\n'). For 319 output used fun. 320 321 @param fun: Function for output (L{write} or L{fwrite} for example). 322 @type fun: func 323 @param arg: Object to output. All objects convert to string I{str()} function. 324 @type arg: *object 325 @return: None. 326 @rtype: None 327 @note: For work this function will be call L{fwrite} function. 328 """ 329 fun((levelbodychar * levelwidth * _level) + levelendchar) 330 fun(*arg ) 331 fun('\n' )
332
333 -def fwriteln(*arg):
334 """ 335 Write concatenated arguments into fstream and append new line ('\\n'). 336 337 @param arg: Object to output. All objects convert to string I{str()} function. 338 @type arg: *object 339 @return: None. 340 @rtype: None 341 @note: For work this function will be used L{fwrite} function. 342 """ 343 _writeln(fwrite, *arg)
344
345 -def writeln(*arg):
346 """ 347 Write concatenated arguments into outstream and append new line ('\\n'). 348 349 @param arg: Object to output. All objects convert to string I{str()} function. 350 @type arg: *object 351 @return: None. 352 @rtype: None 353 @note: For work this function will be used L{write} function. 354 """ 355 _writeln(write, *arg)
356
357 -def _rwrite(fun, *arg):
358 """ 359 As L{fwrite} but return arguments tuple and for output use fun. 360 361 @param fun: Function for output (L{write} or L{fwrite} for example). 362 @type fun: func 363 @param arg: Object to output. All objects convert to string I{str()} function. 364 @type arg: *object 365 @return: Arguments tuple. 366 @rtype: tuple 367 """ 368 fun(*arg) 369 return arg
370
371 -def frwrite(*arg):
372 """ 373 As L{fwrite} but return arguments tuple. 374 375 @param arg: Object to output. All objects convert to string I{str()} function. 376 @type arg: *object 377 @return: Arguments tuple. 378 @rtype: tuple 379 """ 380 return _rwrite(fwrite, *arg)
381
382 -def rwrite(*arg):
383 """ 384 As L{write} but return arguments tuple. 385 386 @param arg: Object to output. All objects convert to string I{str()} function. 387 @type arg: *object 388 @return: Arguments tuple. 389 @rtype: tuple 390 """ 391 return _rwrite(write, *arg)
392
393 -def _eval(fun, expr, g=globals(), l=locals()):
394 """ 395 Write expr, evaluate it and write result to output using fun. 396 397 Write algorithm: 398 - write L{desceval} and expr in quotes. 399 - evaluate expr using eval. 400 - if exception occur then write L{descevalexc} and quoted exception. 401 - if no error then write L{descevalrez} and quoted result. 402 - write L{descevalln}. 403 404 Then write this function you must get globals() and locals() if you using 405 global or local scope variables into exprwssion. 406 407 For example see L{weval}. 408 409 @param fun: Function for output (L{write} or L{fwrite} for example). 410 @type fun: func 411 @param expr: Expression string. 412 @type expr: str 413 @param g: Global variables. 414 @type g: dict = globals() 415 @param l: Local variables. 416 @type l: dict = locals() 417 @return: Result of evaluation or Exception. 418 @rtype: object or Exception 419 """ 420 fun(desceval, '"', expr, '"') 421 exc = False 422 try: 423 er = eval(expr, g, l) 424 except Exception, e: 425 exc = True 426 er = e 427 if exc: 428 fun(descevalexc, '"', er, '"') 429 else: 430 fun(descevalrez, '"', er, '"') 431 if descevalln: 432 fun(descevalln) 433 return er
434
435 -def weval(expr, g=globals(), l=locals()):
436 """ 437 Write expr, evaluate it and write result to outstream. 438 439 Write algorithm: 440 - write L{desceval} and expr in quotes. 441 - evaluate expr using eval. 442 - if exception occur then write L{descevalexc} and quoted exception. 443 - if no error then write L{descevalrez} and quoted result. 444 - write L{descevalln}. 445 446 Then write this function you must get globals() and locals() if you using 447 global or local scope variables into exprwssion. 448 449 For example: C{ dbg.weval('dir(a)', globals(), locals()) } 450 451 @param expr: Expression string. 452 @type expr: str 453 @param g: Global variables. 454 @type g: dict = globals() 455 @param l: Local variables. 456 @type l: dict = locals() 457 @return: Result of evaluation or Exception. 458 @rtype: object or Exception 459 """ 460 return _eval(writeln, expr,g, l)
461
462 -def fweval(expr, g=globals(), l=locals()):
463 """ 464 Write expr, evaluate it and write result to fstream. 465 466 Write algorithm: 467 - write L{desceval} and expr in quotes. 468 - evaluate expr using eval. 469 - if exception occur then write L{descevalexc} and quoted exception. 470 - if no error then write L{descevalrez} and quoted result. 471 - write L{descevalln}. 472 473 Then write this function you must get globals() and locals() if you using 474 global or local scope variables into exprwssion. 475 476 For example: C{ dbg.feval('dir(a)', globals(), locals()) } 477 478 @param expr: Expression string. 479 @type expr: str 480 @param g: Global variables. 481 @type g: dict = globals() 482 @param l: Local variables. 483 @type l: dict = locals() 484 @return: Result of evaluation or Exception. 485 @rtype: object or Exception 486 """ 487 return _eval(fwriteln, expr, g, l)
488 489 490 491 #------------------------------------------------------------------------------- 492 493 # Register shutdown function. 494 atexit.register(shutdown) 495 496 497 498 #-DEBUG-START------------------------------------------------------------------- 499
500 -def _debug():
501 """ 502 Test function. 503 504 Output to outstream is a next:: 505 506 *** DEBUG START *** 507 508 >456 509 ..>tst1:test 510 >CALL tst2() 511 ..>tst2 start 512 ..>tst1:from tst2 513 ..>CALL tst3() 514 ....>tst3 515 ..>RET from tst3() 516 ..>tst2 end 517 >RET from tst2() 518 >CALL tst2() 519 ..>tst2 start 520 ..>tst1:from tst2 521 ..>CALL tst3() 522 ....>tst3 523 ..>RET from tst3() 524 ..>tst2 end 525 >RET from tst2() 526 arg1arg2> 527 rwrite return: ('arg1', 'arg2') 528 >EVAL: "str(5+6)" 529 > ER="11" 530 > 531 > 532 weval return: 11 533 >CALL tst4() 534 >RET from tst4() 535 >Exception OK 536 537 538 *** DEBUG END *** 539 540 """ 541 def tst1(a): 542 writeln('tst1:', a)
543 544 @wlevel 545 def tst2(): 546 writeln('tst2 start') 547 tst1('from tst2') 548 tst3() 549 writeln('tst2 end') 550 551 @wlevel 552 def tst3(): 553 writeln('tst3') 554 print tst3.func_name 555 556 @wlevel 557 def tst4(): 558 raise AttributeError 559 560 writeln(456) 561 fwriteln(456) 562 lvlup() 563 tst1('test') 564 lvldown() 565 tst2() 566 lvldown() 567 lvldown() 568 lvldown() 569 tst2() 570 writeln('\nrwrite return: %s' % (rwrite('arg1', 'arg2'), ) ) 571 writeln('\nweval return: %s' % (weval('str(5+6)'), ) ) 572 try: 573 tst4() 574 except AttributeError: 575 writeln('Exception OK') 576 else: 577 writeln('Exception fails') 578 579 pass 580 581 #-DEBUG-END--------------------------------------------------------------------- 582 583 if __name__=='__main__': 584 _debug() 585