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