Home | History | Annotate | Download | only in python
      1 import sys
      2 import inspect
      3 from collections import OrderedDict
      4 
      5 class TracebackFancy:
      6 	def __init__(self,traceback):
      7 		self.t = traceback
      8 
      9 	def getFrame(self):
     10 		return FrameFancy(self.t.tb_frame)
     11 
     12 	def getLineNumber(self):
     13 		return self.t.tb_lineno if self.t != None else None
     14 
     15 	def getNext(self):
     16 		return TracebackFancy(self.t.tb_next)
     17 
     18 	def __str__(self):
     19 		if self.t == None:
     20 			return ""
     21 		str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber())
     22 		return str_self + "\n" + self.getNext().__str__()
     23 
     24 class ExceptionFancy:
     25 	def __init__(self,frame):
     26 		self.etraceback = frame.f_exc_traceback
     27 		self.etype = frame.exc_type
     28 		self.evalue = frame.f_exc_value
     29 
     30 	def __init__(self,tb,ty,va):
     31 		self.etraceback = tb
     32 		self.etype = ty
     33 		self.evalue = va
     34 
     35 	def getTraceback(self):
     36 		return TracebackFancy(self.etraceback)
     37 
     38 	def __nonzero__(self):
     39 		return self.etraceback != None or self.etype != None or self.evalue != None
     40 
     41 	def getType(self):
     42 		return str(self.etype)
     43 
     44 	def getValue(self):
     45 		return self.evalue
     46 
     47 class CodeFancy:
     48 	def __init__(self,code):
     49 		self.c = code
     50 
     51 	def getArgCount(self):
     52 		return self.c.co_argcount if self.c != None else 0
     53 
     54 	def getFilename(self):
     55 		return self.c.co_filename if self.c != None else ""
     56 
     57 	def getVariables(self):
     58 		return self.c.co_varnames if self.c != None else []
     59 
     60 	def getName(self):
     61 		return self.c.co_name if self.c != None else ""
     62 
     63 	def getFileName(self):
     64 		return self.c.co_filename if self.c != None else ""
     65 
     66 class ArgsFancy:
     67 	def __init__(self,frame,arginfo):
     68 		self.f = frame
     69 		self.a = arginfo
     70 
     71 	def __str__(self):
     72 		args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
     73 		ret = ""
     74 		count = 0
     75 		size = len(args)
     76 		for arg in args:
     77 			ret = ret + ("%s = %s" % (arg, args[arg]))
     78 			count = count + 1
     79 			if count < size:
     80 				ret = ret + ", "
     81 		if varargs:
     82 			if size > 0:
     83 				ret = ret + " "
     84 			ret = ret + "varargs are " + str(varargs)
     85 		if kwargs:
     86 			if size > 0:
     87 				ret = ret + " "
     88 			ret = ret + "kwargs are " + str(kwargs)
     89 		return ret
     90 
     91 	def getNumArgs(wantVarargs = False, wantKWArgs=False):
     92 		args, varargs, keywords, values = self.a
     93 		size = len(args)
     94 		if varargs and wantVarargs:
     95 			size = size+len(self.getVarArgs())
     96 		if keywords and wantKWArgs:
     97 			size = size+len(self.getKWArgs())
     98 		return size
     99 
    100 	def getArgs(self):
    101 		args, _, _, values = self.a
    102 		argWValues = OrderedDict()
    103 		for arg in args:
    104 			argWValues[arg] = values[arg]
    105 		return argWValues
    106 
    107 	def getVarArgs(self):
    108 		_, vargs, _, _ = self.a
    109 		if vargs:
    110 			return self.f.f_locals[vargs]
    111 		return ()
    112 
    113 	def getKWArgs(self):
    114 		_, _, kwargs, _ = self.a
    115 		if kwargs:
    116 			return self.f.f_locals[kwargs]
    117 		return {}
    118 
    119 class FrameFancy:
    120 	def __init__(self,frame):
    121 		self.f = frame
    122 
    123 	def getCaller(self):
    124 		return FrameFancy(self.f.f_back)
    125 
    126 	def getLineNumber(self):
    127 		return self.f.f_lineno if self.f != None else 0
    128 
    129 	def getCodeInformation(self):
    130 		return CodeFancy(self.f.f_code) if self.f != None else None
    131 
    132 	def getExceptionInfo(self):
    133 		return ExceptionFancy(self.f) if self.f != None else None
    134 
    135 	def getName(self):
    136 		return self.getCodeInformation().getName() if self.f != None else ""
    137 
    138 	def getFileName(self):
    139 		return self.getCodeInformation().getFileName() if self.f != None else ""
    140 
    141 	def getLocals(self):
    142 		return self.f.f_locals if self.f != None else {}
    143 		
    144 	def getArgumentInfo(self):
    145 		return ArgsFancy(self.f,inspect.getargvalues(self.f)) if self.f != None else None
    146 
    147 class TracerClass:
    148 	def callEvent(self,frame):
    149 		pass
    150 
    151 	def lineEvent(self,frame):
    152 		pass
    153 
    154 	def returnEvent(self,frame,retval):
    155 		pass
    156 
    157 	def exceptionEvent(self,frame,exception,value,traceback):
    158 		pass
    159 
    160 	def cCallEvent(self,frame,cfunct):
    161 		pass
    162 
    163 	def cReturnEvent(self,frame,cfunct):
    164 		pass
    165 
    166 	def cExceptionEvent(self,frame,cfunct):
    167 		pass
    168 
    169 tracer_impl = TracerClass()
    170 
    171 
    172 def the_tracer_entrypoint(frame,event,args):
    173 	if tracer_impl == None:
    174 		return None
    175 	if event == "call":
    176 		call_retval = tracer_impl.callEvent(FrameFancy(frame))
    177 		if call_retval == False:
    178 			return None
    179 		return the_tracer_entrypoint
    180 	elif event == "line":
    181 		line_retval = tracer_impl.lineEvent(FrameFancy(frame))
    182 		if line_retval == False:
    183 			return None
    184 		return the_tracer_entrypoint
    185 	elif event == "return":
    186 		tracer_impl.returnEvent(FrameFancy(frame),args)
    187 	elif event == "exception":
    188 		exty,exva,extb = args
    189 		exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva))
    190 		if exception_retval == False:
    191 			return None
    192 		return the_tracer_entrypoint
    193 	elif event == "c_call":
    194 		tracer_impl.cCallEvent(FrameFancy(frame),args)
    195 	elif event == "c_return":
    196 		tracer_impl.cReturnEvent(FrameFancy(frame),args)
    197 	elif event == "c_exception":
    198 		tracer_impl.cExceptionEvent(FrameFancy(frame),args)
    199 	return None
    200 
    201 def enable(t=None):
    202 	global tracer_impl
    203 	if t:
    204 		tracer_impl = t
    205 	sys.settrace(the_tracer_entrypoint)
    206 
    207 def disable():
    208 	sys.settrace(None)
    209 
    210 class LoggingTracer:
    211 	def callEvent(self,frame):
    212 		print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
    213 
    214 	def lineEvent(self,frame):
    215 		print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName()
    216 
    217 	def returnEvent(self,frame,retval):
    218 		print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())
    219 
    220 	def exceptionEvent(self,frame,exception):
    221 		print "exception %s %s raised from %s @ %s" %  (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
    222 		print "tb: " + str(exception.getTraceback())
    223 
    224 # the same functionality as LoggingTracer, but with a little more lldb-specific smarts
    225 class LLDBAwareTracer:
    226 	def callEvent(self,frame):
    227 		if frame.getName() == "<module>":
    228 			return
    229 		if frame.getName() == "run_one_line":
    230 			print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])
    231 			return
    232 		if "Python.framework" in frame.getFileName():
    233 			print "call into Python at " + frame.getName()
    234 			return
    235 		if frame.getName() == "__init__" and frame.getCaller().getName() == "run_one_line" and frame.getCaller().getLineNumber() == 101:
    236 			return False
    237 		strout = "call " + frame.getName()
    238 		if (frame.getCaller().getFileName() == ""):
    239 			strout += " from LLDB - args are "
    240 			args = frame.getArgumentInfo().getArgs()
    241 			for arg in args:
    242 				if arg == "dict" or arg == "internal_dict":
    243 					continue
    244 				strout = strout + ("%s = %s " % (arg,args[arg]))
    245 		else:
    246 			strout += " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
    247 		print strout
    248 
    249 	def lineEvent(self,frame):
    250 		if frame.getName() == "<module>":
    251 			return
    252 		if frame.getName() == "run_one_line":
    253 			print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"],frame.getLineNumber())
    254 			return
    255 		if "Python.framework" in frame.getFileName():
    256 			print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber())
    257 			return
    258 		strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " 
    259 		if (frame.getCaller().getFileName() == ""):
    260 			locals = frame.getLocals()
    261 			for local in locals:
    262 				if local == "dict" or local == "internal_dict":
    263 					continue
    264 				strout = strout + ("%s = %s " % (local,locals[local]))
    265 		else:
    266 			strout = strout + str(frame.getLocals())
    267 		strout = strout + " in " + frame.getFileName()
    268 		print strout
    269 
    270 	def returnEvent(self,frame,retval):
    271 		if frame.getName() == "<module>":
    272 			return
    273 		if frame.getName() == "run_one_line":
    274 			print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"],retval)
    275 			return
    276 		if "Python.framework" in frame.getFileName():
    277 			print "return from Python at " + frame.getName() + " return value is " + str(retval)
    278 			return
    279 		strout = "return from " + frame.getName() + " return value is " + str(retval) + " locals are "
    280 		if (frame.getCaller().getFileName() == ""):
    281 			locals = frame.getLocals()
    282 			for local in locals:
    283 				if local == "dict" or local == "internal_dict":
    284 					continue
    285 				strout = strout + ("%s = %s " % (local,locals[local]))
    286 		else:
    287 			strout = strout + str(frame.getLocals())
    288 		strout = strout + " in " + frame.getFileName()
    289 		print strout
    290 
    291 	def exceptionEvent(self,frame,exception):
    292 		if frame.getName() == "<module>":
    293 			return
    294 		print "exception %s %s raised from %s @ %s" %  (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
    295 		print "tb: " + str(exception.getTraceback())
    296 
    297 def f(x,y=None):
    298 	if x > 0:
    299 		return 2 + f(x-2)
    300 	return 35
    301 
    302 def g(x):
    303 	return 1.134 / x
    304 
    305 def print_keyword_args(**kwargs):
    306      # kwargs is a dict of the keyword args passed to the function
    307      for key, value in kwargs.iteritems():
    308          print "%s = %s" % (key, value)
    309 
    310 def total(initial=5, *numbers, **keywords):
    311     count = initial
    312     for number in numbers:
    313         count += number
    314     for key in keywords:
    315         count += keywords[key]
    316     return count
    317 
    318 if __name__ == "__main__":
    319 	enable(LoggingTracer())
    320 	f(5)
    321 	f(5,1)
    322 	print_keyword_args(first_name="John", last_name="Doe")
    323 	total(10, 1, 2, 3, vegetables=50, fruits=100)
    324 	try:
    325 		g(0)
    326 	except:
    327 		pass
    328 	disable()
    329