Nasty way to get your debugging functions available everywhere.
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 | __all__=[]
_rgb_files = [open('/tmp/rgb_debug.txt','w')]
import sys, time
_rgb_auto_flush=1
def rgb_time(offs=1):
t = time.time()
if offs: return t-_rgb_t0
return t
_rgb_t0=rgb_time(0)
def rgb_debug(*msg,**kwds):
msg = ' '.join(map(str,msg)) + '\n'
for f in _rgb_files:
f.write(msg)
if _rgb_auto_flush:
flush = getattr(f,'flush',None)
if flush: flush()
def rgb_pprint(*obj):
if obj:
if isinstance(obj[0],(str,unicode)):
rgb_debug(obj[0])
obj = obj[1:]
import pprint
for o in obj:
for f in _rgb_files:
pprint.pprint(o,f)
def rgb_stack(*msg,**kwds):
import inspect
rgb_debug(*msg)
i = 1
while 1:
f = sys._getframe(i)
if f.f_globals.get('_rgb_t0',None) is not _rgb_t0: break
i += 1
F = inspect.stack()
frameCount = kwds.get('_frameCount',0)
showLocals = kwds.get('_showLocals',0)
if not frameCount:
F = F[i:]
else:
F = F[i:i+frameCount]
for f in F:
rgb_debug('file:',f[1],'line:',f[2],'in',f[3])
for l in f[4]: rgb_debug(l)
if showLocals:
rgb_debug(' locals=%r' % f[0].f_locals)
class _RGB_Wrapper(object):
def __init__(self,func,funcname=None,show=0,show_kwds={}):
self.func = func
self.funcname = funcname or func.__name__
if not callable(show):
show=show and rgb_stack or rgb_debug
self.show = show
self.show_kwds= show_kwds
self.called = 0
def __call__(self,*args,**kwds):
func = self.func
if not self.called:
self.called = 1
try:
self.show('%s(*%r,**%r) called' % (self.funcname,args,kwds),**self.show_kwds)
finally:
self.called = 0
return func(*args,**kwds)
def rgb_wrap(func,show=1,funcname=None,show_kwds={}):
return _RGB_Wrapper(func,funcname,show,show_kwds=show_kwds)
class rgb_watch_writes:
def __init__(self,f,cb,*cbargs):
self._f = f
self._cb = cb
self._cbargs = cbargs
def write(self,msg):
self._cb(*((msg,)+self._cbargs))
self._f.write(msg)
def __getattr__(self,a):
return getattr(self._f,a)
def rgb_print_exc(*msg):
if msg: rgb_debug(*msg)
import traceback
for f in _rgb_files: traceback.print_exc(file=f)
if _rgb_auto_flush: rgb_flush()
def rgb_add_file(f):
if f not in _rgb_files: _rgb_files.append(f)
def rgb_auto_flush(v=1):
_rgb_auto_flush=v
def rgb_flush():
for f in _rgb_files:
flush = getattr(f,'flush',None)
if flush: flush()
import __builtin__
__builtin__.rgb_debug = rgb_debug
__builtin__.rgb_stack = rgb_stack
__builtin__.rgb_pprint = rgb_pprint
__builtin__.rgb_time = rgb_time
__builtin__.rgb_print_exc = rgb_print_exc
__builtin__.rgb_auto_flush = rgb_auto_flush
__builtin__.rgb_flush = rgb_flush
__builtin__.rgb_wrap = rgb_wrap
__builtin__.rgb_add_file = rgb_add_file
__builtin__.rgb_watch_writes = rgb_watch_writes
rgb_debug.__module__=sys.modules['rgb_debug']
sys.modules['rgb_debug'] = rgb_debug
|
I often have to debug applications run by other processes eg apache. I want to put print statements in, but they're not allowed in the process context. This recipe allows me to do
import rgb_debug rgb_debug('this is a debug',i,j)
and get the values dumped out into a file called /tmp/rgb_debug.txt; the recipe uses __builtin__ to make the various functions immediately available everywhere in the application. A typical usage might be to insert the import rgb_debug into the start cgi_script and then the functions can be used elsewhere without doing imports.
Another usage is to find out where a particular print gets done eg
import rgb_debug def print_cb(msg): if msg!='debug:': rgb_stack('found garbage:'+msg) os._exit(1) sys.stdout = rgb_watch_writes(sys.stdout,print_cb)
this finds out where you left that print "debug:".
I suppose this kind of code will eventually get disallowed as it really abuses some common structures. I can't remember where the original idea came from, but I think it might have been John J Lee.
Moronically I got the syntax wrong for the examples eg
In EasyExtend I've written following function that maps module attributes into builtins.
The __publish__ attribute is somewhat analog to the __all__ module attribute. It is more declarative which means that control logic is avoided in the module scope. Otherwise one has to care for the function to be actually called. This can be achieved within an import_hook for example.