1*525cd59fSSerge Gueltonfrom __future__ import print_function
2c8b36f16SEnrico Granataimport sys
3c8b36f16SEnrico Granataimport inspect
4c8b36f16SEnrico Granatafrom collections import OrderedDict
5c8b36f16SEnrico Granata
6b9c1b51eSKate Stone
7c8b36f16SEnrico Granataclass TracebackFancy:
8b9c1b51eSKate Stone
9c8b36f16SEnrico Granata    def __init__(self, traceback):
10c8b36f16SEnrico Granata        self.t = traceback
11c8b36f16SEnrico Granata
12c8b36f16SEnrico Granata    def getFrame(self):
13c8b36f16SEnrico Granata        return FrameFancy(self.t.tb_frame)
14c8b36f16SEnrico Granata
15c8b36f16SEnrico Granata    def getLineNumber(self):
16b9c1b51eSKate Stone        return self.t.tb_lineno if self.t is not None else None
17c8b36f16SEnrico Granata
18c8b36f16SEnrico Granata    def getNext(self):
19c8b36f16SEnrico Granata        return TracebackFancy(self.t.tb_next)
20c8b36f16SEnrico Granata
21c8b36f16SEnrico Granata    def __str__(self):
22b9c1b51eSKate Stone        if self.t is None:
23c8b36f16SEnrico Granata            return ""
24b9c1b51eSKate Stone        str_self = "%s @ %s" % (
25b9c1b51eSKate Stone            self.getFrame().getName(), self.getLineNumber())
26c8b36f16SEnrico Granata        return str_self + "\n" + self.getNext().__str__()
27c8b36f16SEnrico Granata
28b9c1b51eSKate Stone
29c8b36f16SEnrico Granataclass ExceptionFancy:
30b9c1b51eSKate Stone
31c8b36f16SEnrico Granata    def __init__(self, frame):
32c8b36f16SEnrico Granata        self.etraceback = frame.f_exc_traceback
33c8b36f16SEnrico Granata        self.etype = frame.exc_type
34c8b36f16SEnrico Granata        self.evalue = frame.f_exc_value
35c8b36f16SEnrico Granata
36c8b36f16SEnrico Granata    def __init__(self, tb, ty, va):
37c8b36f16SEnrico Granata        self.etraceback = tb
38c8b36f16SEnrico Granata        self.etype = ty
39c8b36f16SEnrico Granata        self.evalue = va
40c8b36f16SEnrico Granata
41c8b36f16SEnrico Granata    def getTraceback(self):
42c8b36f16SEnrico Granata        return TracebackFancy(self.etraceback)
43c8b36f16SEnrico Granata
44c8b36f16SEnrico Granata    def __nonzero__(self):
45b9c1b51eSKate Stone        return self.etraceback is not None or self.etype is not None or self.evalue is not None
46c8b36f16SEnrico Granata
47c8b36f16SEnrico Granata    def getType(self):
48c8b36f16SEnrico Granata        return str(self.etype)
49c8b36f16SEnrico Granata
50c8b36f16SEnrico Granata    def getValue(self):
51c8b36f16SEnrico Granata        return self.evalue
52c8b36f16SEnrico Granata
53b9c1b51eSKate Stone
54c8b36f16SEnrico Granataclass CodeFancy:
55b9c1b51eSKate Stone
56c8b36f16SEnrico Granata    def __init__(self, code):
57c8b36f16SEnrico Granata        self.c = code
58c8b36f16SEnrico Granata
59c8b36f16SEnrico Granata    def getArgCount(self):
60b9c1b51eSKate Stone        return self.c.co_argcount if self.c is not None else 0
61c8b36f16SEnrico Granata
62c8b36f16SEnrico Granata    def getFilename(self):
63b9c1b51eSKate Stone        return self.c.co_filename if self.c is not None else ""
64c8b36f16SEnrico Granata
65c8b36f16SEnrico Granata    def getVariables(self):
66b9c1b51eSKate Stone        return self.c.co_varnames if self.c is not None else []
67c8b36f16SEnrico Granata
68c8b36f16SEnrico Granata    def getName(self):
69b9c1b51eSKate Stone        return self.c.co_name if self.c is not None else ""
7078f05f13SEnrico Granata
7178f05f13SEnrico Granata    def getFileName(self):
72b9c1b51eSKate Stone        return self.c.co_filename if self.c is not None else ""
73b9c1b51eSKate Stone
74c8b36f16SEnrico Granata
75c8b36f16SEnrico Granataclass ArgsFancy:
76b9c1b51eSKate Stone
77c8b36f16SEnrico Granata    def __init__(self, frame, arginfo):
78c8b36f16SEnrico Granata        self.f = frame
79c8b36f16SEnrico Granata        self.a = arginfo
80c8b36f16SEnrico Granata
81c8b36f16SEnrico Granata    def __str__(self):
82c8b36f16SEnrico Granata        args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
83c8b36f16SEnrico Granata        ret = ""
84c8b36f16SEnrico Granata        count = 0
85c8b36f16SEnrico Granata        size = len(args)
86c8b36f16SEnrico Granata        for arg in args:
87c8b36f16SEnrico Granata            ret = ret + ("%s = %s" % (arg, args[arg]))
88c8b36f16SEnrico Granata            count = count + 1
89c8b36f16SEnrico Granata            if count < size:
90c8b36f16SEnrico Granata                ret = ret + ", "
91c8b36f16SEnrico Granata        if varargs:
92c8b36f16SEnrico Granata            if size > 0:
93c8b36f16SEnrico Granata                ret = ret + " "
94c8b36f16SEnrico Granata            ret = ret + "varargs are " + str(varargs)
95c8b36f16SEnrico Granata        if kwargs:
96c8b36f16SEnrico Granata            if size > 0:
97c8b36f16SEnrico Granata                ret = ret + " "
98c8b36f16SEnrico Granata            ret = ret + "kwargs are " + str(kwargs)
99c8b36f16SEnrico Granata        return ret
100c8b36f16SEnrico Granata
101c8b36f16SEnrico Granata    def getNumArgs(wantVarargs=False, wantKWArgs=False):
102c8b36f16SEnrico Granata        args, varargs, keywords, values = self.a
103c8b36f16SEnrico Granata        size = len(args)
104c8b36f16SEnrico Granata        if varargs and wantVarargs:
105c8b36f16SEnrico Granata            size = size + len(self.getVarArgs())
106c8b36f16SEnrico Granata        if keywords and wantKWArgs:
107c8b36f16SEnrico Granata            size = size + len(self.getKWArgs())
108c8b36f16SEnrico Granata        return size
109c8b36f16SEnrico Granata
110c8b36f16SEnrico Granata    def getArgs(self):
111c8b36f16SEnrico Granata        args, _, _, values = self.a
112c8b36f16SEnrico Granata        argWValues = OrderedDict()
113c8b36f16SEnrico Granata        for arg in args:
114c8b36f16SEnrico Granata            argWValues[arg] = values[arg]
115c8b36f16SEnrico Granata        return argWValues
116c8b36f16SEnrico Granata
117c8b36f16SEnrico Granata    def getVarArgs(self):
118c8b36f16SEnrico Granata        _, vargs, _, _ = self.a
119c8b36f16SEnrico Granata        if vargs:
120c8b36f16SEnrico Granata            return self.f.f_locals[vargs]
121c8b36f16SEnrico Granata        return ()
122c8b36f16SEnrico Granata
123c8b36f16SEnrico Granata    def getKWArgs(self):
124c8b36f16SEnrico Granata        _, _, kwargs, _ = self.a
125c8b36f16SEnrico Granata        if kwargs:
126c8b36f16SEnrico Granata            return self.f.f_locals[kwargs]
127c8b36f16SEnrico Granata        return {}
128c8b36f16SEnrico Granata
129b9c1b51eSKate Stone
130c8b36f16SEnrico Granataclass FrameFancy:
131b9c1b51eSKate Stone
132c8b36f16SEnrico Granata    def __init__(self, frame):
133c8b36f16SEnrico Granata        self.f = frame
134c8b36f16SEnrico Granata
135c8b36f16SEnrico Granata    def getCaller(self):
136c8b36f16SEnrico Granata        return FrameFancy(self.f.f_back)
137c8b36f16SEnrico Granata
138c8b36f16SEnrico Granata    def getLineNumber(self):
139b9c1b51eSKate Stone        return self.f.f_lineno if self.f is not None else 0
140c8b36f16SEnrico Granata
141c8b36f16SEnrico Granata    def getCodeInformation(self):
142b9c1b51eSKate Stone        return CodeFancy(self.f.f_code) if self.f is not None else None
143c8b36f16SEnrico Granata
144c8b36f16SEnrico Granata    def getExceptionInfo(self):
145b9c1b51eSKate Stone        return ExceptionFancy(self.f) if self.f is not None else None
146c8b36f16SEnrico Granata
147c8b36f16SEnrico Granata    def getName(self):
148b9c1b51eSKate Stone        return self.getCodeInformation().getName() if self.f is not None else ""
14978f05f13SEnrico Granata
15078f05f13SEnrico Granata    def getFileName(self):
151b9c1b51eSKate Stone        return self.getCodeInformation().getFileName() if self.f is not None else ""
152c8b36f16SEnrico Granata
153c8b36f16SEnrico Granata    def getLocals(self):
154b9c1b51eSKate Stone        return self.f.f_locals if self.f is not None else {}
155c8b36f16SEnrico Granata
156c8b36f16SEnrico Granata    def getArgumentInfo(self):
157b9c1b51eSKate Stone        return ArgsFancy(
158b9c1b51eSKate Stone            self.f, inspect.getargvalues(
159b9c1b51eSKate Stone                self.f)) if self.f is not None else None
160b9c1b51eSKate Stone
161c8b36f16SEnrico Granata
162c8b36f16SEnrico Granataclass TracerClass:
163b9c1b51eSKate Stone
164c8b36f16SEnrico Granata    def callEvent(self, frame):
165c8b36f16SEnrico Granata        pass
166c8b36f16SEnrico Granata
167c8b36f16SEnrico Granata    def lineEvent(self, frame):
168c8b36f16SEnrico Granata        pass
169c8b36f16SEnrico Granata
170c8b36f16SEnrico Granata    def returnEvent(self, frame, retval):
171c8b36f16SEnrico Granata        pass
172c8b36f16SEnrico Granata
173c8b36f16SEnrico Granata    def exceptionEvent(self, frame, exception, value, traceback):
174c8b36f16SEnrico Granata        pass
175c8b36f16SEnrico Granata
176c8b36f16SEnrico Granata    def cCallEvent(self, frame, cfunct):
177c8b36f16SEnrico Granata        pass
178c8b36f16SEnrico Granata
179c8b36f16SEnrico Granata    def cReturnEvent(self, frame, cfunct):
180c8b36f16SEnrico Granata        pass
181c8b36f16SEnrico Granata
182c8b36f16SEnrico Granata    def cExceptionEvent(self, frame, cfunct):
183c8b36f16SEnrico Granata        pass
184c8b36f16SEnrico Granata
185c8b36f16SEnrico Granatatracer_impl = TracerClass()
186c8b36f16SEnrico Granata
187c8b36f16SEnrico Granata
188c8b36f16SEnrico Granatadef the_tracer_entrypoint(frame, event, args):
189b9c1b51eSKate Stone    if tracer_impl is None:
190c8b36f16SEnrico Granata        return None
191c8b36f16SEnrico Granata    if event == "call":
192c8b36f16SEnrico Granata        call_retval = tracer_impl.callEvent(FrameFancy(frame))
193b9c1b51eSKate Stone        if not call_retval:
194c8b36f16SEnrico Granata            return None
195c8b36f16SEnrico Granata        return the_tracer_entrypoint
196c8b36f16SEnrico Granata    elif event == "line":
197c8b36f16SEnrico Granata        line_retval = tracer_impl.lineEvent(FrameFancy(frame))
198b9c1b51eSKate Stone        if not line_retval:
199c8b36f16SEnrico Granata            return None
200c8b36f16SEnrico Granata        return the_tracer_entrypoint
201c8b36f16SEnrico Granata    elif event == "return":
202c8b36f16SEnrico Granata        tracer_impl.returnEvent(FrameFancy(frame), args)
203c8b36f16SEnrico Granata    elif event == "exception":
204c8b36f16SEnrico Granata        exty, exva, extb = args
205b9c1b51eSKate Stone        exception_retval = tracer_impl.exceptionEvent(
206b9c1b51eSKate Stone            FrameFancy(frame), ExceptionFancy(extb, exty, exva))
207b9c1b51eSKate Stone        if not exception_retval:
208c8b36f16SEnrico Granata            return None
209c8b36f16SEnrico Granata        return the_tracer_entrypoint
210c8b36f16SEnrico Granata    elif event == "c_call":
211c8b36f16SEnrico Granata        tracer_impl.cCallEvent(FrameFancy(frame), args)
212c8b36f16SEnrico Granata    elif event == "c_return":
213c8b36f16SEnrico Granata        tracer_impl.cReturnEvent(FrameFancy(frame), args)
214c8b36f16SEnrico Granata    elif event == "c_exception":
215c8b36f16SEnrico Granata        tracer_impl.cExceptionEvent(FrameFancy(frame), args)
216c8b36f16SEnrico Granata    return None
217c8b36f16SEnrico Granata
218b9c1b51eSKate Stone
219c8b36f16SEnrico Granatadef enable(t=None):
220c8b36f16SEnrico Granata    global tracer_impl
221c8b36f16SEnrico Granata    if t:
222c8b36f16SEnrico Granata        tracer_impl = t
223c8b36f16SEnrico Granata    sys.settrace(the_tracer_entrypoint)
224c8b36f16SEnrico Granata
225b9c1b51eSKate Stone
226c8b36f16SEnrico Granatadef disable():
227c8b36f16SEnrico Granata    sys.settrace(None)
228c8b36f16SEnrico Granata
229b9c1b51eSKate Stone
230c8b36f16SEnrico Granataclass LoggingTracer:
231b9c1b51eSKate Stone
232c8b36f16SEnrico Granata    def callEvent(self, frame):
233*525cd59fSSerge Guelton        print("call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()))
234c8b36f16SEnrico Granata
235c8b36f16SEnrico Granata    def lineEvent(self, frame):
236*525cd59fSSerge Guelton        print("running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName())
237c8b36f16SEnrico Granata
238c8b36f16SEnrico Granata    def returnEvent(self, frame, retval):
239*525cd59fSSerge Guelton        print("return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals()))
240c8b36f16SEnrico Granata
241c8b36f16SEnrico Granata    def exceptionEvent(self, frame, exception):
242*525cd59fSSerge Guelton        print("exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()))
243*525cd59fSSerge Guelton        print("tb: " + str(exception.getTraceback()))
244c8b36f16SEnrico Granata
245b9c1b51eSKate Stone# the same functionality as LoggingTracer, but with a little more
246b9c1b51eSKate Stone# lldb-specific smarts
247b9c1b51eSKate Stone
248b9c1b51eSKate Stone
24978f05f13SEnrico Granataclass LLDBAwareTracer:
250b9c1b51eSKate Stone
25178f05f13SEnrico Granata    def callEvent(self, frame):
25278f05f13SEnrico Granata        if frame.getName() == "<module>":
25378f05f13SEnrico Granata            return
25478f05f13SEnrico Granata        if frame.getName() == "run_one_line":
255*525cd59fSSerge Guelton            print("call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"]))
25678f05f13SEnrico Granata            return
25778f05f13SEnrico Granata        if "Python.framework" in frame.getFileName():
258*525cd59fSSerge Guelton            print("call into Python at " + frame.getName())
25978f05f13SEnrico Granata            return
260b9c1b51eSKate Stone        if frame.getName() == "__init__" and frame.getCaller().getName(
261b9c1b51eSKate Stone        ) == "run_one_line" and frame.getCaller().getLineNumber() == 101:
26278f05f13SEnrico Granata            return False
26378f05f13SEnrico Granata        strout = "call " + frame.getName()
26478f05f13SEnrico Granata        if (frame.getCaller().getFileName() == ""):
26578f05f13SEnrico Granata            strout += " from LLDB - args are "
26678f05f13SEnrico Granata            args = frame.getArgumentInfo().getArgs()
26778f05f13SEnrico Granata            for arg in args:
26878f05f13SEnrico Granata                if arg == "dict" or arg == "internal_dict":
26978f05f13SEnrico Granata                    continue
27078f05f13SEnrico Granata                strout = strout + ("%s = %s " % (arg, args[arg]))
27178f05f13SEnrico Granata        else:
272b9c1b51eSKate Stone            strout += " from " + frame.getCaller().getName() + " @ " + \
273b9c1b51eSKate Stone                str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
274*525cd59fSSerge Guelton        print(strout)
27578f05f13SEnrico Granata
27678f05f13SEnrico Granata    def lineEvent(self, frame):
27778f05f13SEnrico Granata        if frame.getName() == "<module>":
27878f05f13SEnrico Granata            return
27978f05f13SEnrico Granata        if frame.getName() == "run_one_line":
280*525cd59fSSerge Guelton            print("running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"], frame.getLineNumber()))
28178f05f13SEnrico Granata            return
28278f05f13SEnrico Granata        if "Python.framework" in frame.getFileName():
283*525cd59fSSerge Guelton            print("running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber()))
28478f05f13SEnrico Granata            return
285b9c1b51eSKate Stone        strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + \
286b9c1b51eSKate Stone            " locals are "
28778f05f13SEnrico Granata        if (frame.getCaller().getFileName() == ""):
28878f05f13SEnrico Granata            locals = frame.getLocals()
28978f05f13SEnrico Granata            for local in locals:
29078f05f13SEnrico Granata                if local == "dict" or local == "internal_dict":
29178f05f13SEnrico Granata                    continue
29278f05f13SEnrico Granata                strout = strout + ("%s = %s " % (local, locals[local]))
29378f05f13SEnrico Granata        else:
29478f05f13SEnrico Granata            strout = strout + str(frame.getLocals())
29578f05f13SEnrico Granata        strout = strout + " in " + frame.getFileName()
296*525cd59fSSerge Guelton        print(strout)
29778f05f13SEnrico Granata
29878f05f13SEnrico Granata    def returnEvent(self, frame, retval):
29978f05f13SEnrico Granata        if frame.getName() == "<module>":
30078f05f13SEnrico Granata            return
30178f05f13SEnrico Granata        if frame.getName() == "run_one_line":
302*525cd59fSSerge Guelton            print("return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"], retval))
30378f05f13SEnrico Granata            return
30478f05f13SEnrico Granata        if "Python.framework" in frame.getFileName():
305*525cd59fSSerge Guelton            print("return from Python at " + frame.getName() + " return value is " + str(retval))
30678f05f13SEnrico Granata            return
307b9c1b51eSKate Stone        strout = "return from " + frame.getName() + " return value is " + \
308b9c1b51eSKate Stone            str(retval) + " locals are "
30978f05f13SEnrico Granata        if (frame.getCaller().getFileName() == ""):
31078f05f13SEnrico Granata            locals = frame.getLocals()
31178f05f13SEnrico Granata            for local in locals:
31278f05f13SEnrico Granata                if local == "dict" or local == "internal_dict":
31378f05f13SEnrico Granata                    continue
31478f05f13SEnrico Granata                strout = strout + ("%s = %s " % (local, locals[local]))
31578f05f13SEnrico Granata        else:
31678f05f13SEnrico Granata            strout = strout + str(frame.getLocals())
31778f05f13SEnrico Granata        strout = strout + " in " + frame.getFileName()
318*525cd59fSSerge Guelton        print(strout)
31978f05f13SEnrico Granata
32078f05f13SEnrico Granata    def exceptionEvent(self, frame, exception):
32178f05f13SEnrico Granata        if frame.getName() == "<module>":
32278f05f13SEnrico Granata            return
323*525cd59fSSerge Guelton        print("exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()))
324*525cd59fSSerge Guelton        print("tb: " + str(exception.getTraceback()))
32578f05f13SEnrico Granata
326b9c1b51eSKate Stone
327c8b36f16SEnrico Granatadef f(x, y=None):
328c8b36f16SEnrico Granata    if x > 0:
329c8b36f16SEnrico Granata        return 2 + f(x - 2)
330c8b36f16SEnrico Granata    return 35
331c8b36f16SEnrico Granata
332b9c1b51eSKate Stone
333c8b36f16SEnrico Granatadef g(x):
334c8b36f16SEnrico Granata    return 1.134 / x
335c8b36f16SEnrico Granata
336b9c1b51eSKate Stone
337c8b36f16SEnrico Granatadef print_keyword_args(**kwargs):
338c8b36f16SEnrico Granata    # kwargs is a dict of the keyword args passed to the function
339ce54fa18SSerge Guelton    for key, value in kwargs.items():
340*525cd59fSSerge Guelton        print("%s = %s" % (key, value))
341c8b36f16SEnrico Granata
342b9c1b51eSKate Stone
343c8b36f16SEnrico Granatadef total(initial=5, *numbers, **keywords):
344c8b36f16SEnrico Granata    count = initial
345c8b36f16SEnrico Granata    for number in numbers:
346c8b36f16SEnrico Granata        count += number
347c8b36f16SEnrico Granata    for key in keywords:
348c8b36f16SEnrico Granata        count += keywords[key]
349c8b36f16SEnrico Granata    return count
350c8b36f16SEnrico Granata
351c8b36f16SEnrico Granataif __name__ == "__main__":
352c8b36f16SEnrico Granata    enable(LoggingTracer())
353c8b36f16SEnrico Granata    f(5)
354c8b36f16SEnrico Granata    f(5, 1)
355c8b36f16SEnrico Granata    print_keyword_args(first_name="John", last_name="Doe")
356c8b36f16SEnrico Granata    total(10, 1, 2, 3, vegetables=50, fruits=100)
357c8b36f16SEnrico Granata    try:
358c8b36f16SEnrico Granata        g(0)
359c8b36f16SEnrico Granata    except:
360c8b36f16SEnrico Granata        pass
361c8b36f16SEnrico Granata    disable()
362