1import os 2import sys 3import linecache 4import re 5import Tkinter as tk 6 7from idlelib.TreeWidget import TreeNode, TreeItem, ScrolledCanvas 8from idlelib.ObjectBrowser import ObjectTreeItem, make_objecttreeitem 9from idlelib.PyShell import PyShellFileList 10 11def StackBrowser(root, flist=None, tb=None, top=None): 12 if top is None: 13 top = tk.Toplevel(root) 14 sc = ScrolledCanvas(top, bg="white", highlightthickness=0) 15 sc.frame.pack(expand=1, fill="both") 16 item = StackTreeItem(flist, tb) 17 node = TreeNode(sc.canvas, None, item) 18 node.expand() 19 20class StackTreeItem(TreeItem): 21 22 def __init__(self, flist=None, tb=None): 23 self.flist = flist 24 self.stack = self.get_stack(tb) 25 self.text = self.get_exception() 26 27 def get_stack(self, tb): 28 if tb is None: 29 tb = sys.last_traceback 30 stack = [] 31 if tb and tb.tb_frame is None: 32 tb = tb.tb_next 33 while tb is not None: 34 stack.append((tb.tb_frame, tb.tb_lineno)) 35 tb = tb.tb_next 36 return stack 37 38 def get_exception(self): 39 type = sys.last_type 40 value = sys.last_value 41 if hasattr(type, "__name__"): 42 type = type.__name__ 43 s = str(type) 44 if value is not None: 45 s = s + ": " + str(value) 46 return s 47 48 def GetText(self): 49 return self.text 50 51 def GetSubList(self): 52 sublist = [] 53 for info in self.stack: 54 item = FrameTreeItem(info, self.flist) 55 sublist.append(item) 56 return sublist 57 58class FrameTreeItem(TreeItem): 59 60 def __init__(self, info, flist): 61 self.info = info 62 self.flist = flist 63 64 def GetText(self): 65 frame, lineno = self.info 66 try: 67 modname = frame.f_globals["__name__"] 68 except: 69 modname = "?" 70 code = frame.f_code 71 filename = code.co_filename 72 funcname = code.co_name 73 sourceline = linecache.getline(filename, lineno) 74 sourceline = sourceline.strip() 75 if funcname in ("?", "", None): 76 item = "%s, line %d: %s" % (modname, lineno, sourceline) 77 else: 78 item = "%s.%s(...), line %d: %s" % (modname, funcname, 79 lineno, sourceline) 80 return item 81 82 def GetSubList(self): 83 frame, lineno = self.info 84 sublist = [] 85 if frame.f_globals is not frame.f_locals: 86 item = VariablesTreeItem("<locals>", frame.f_locals, self.flist) 87 sublist.append(item) 88 item = VariablesTreeItem("<globals>", frame.f_globals, self.flist) 89 sublist.append(item) 90 return sublist 91 92 def OnDoubleClick(self): 93 if self.flist: 94 frame, lineno = self.info 95 filename = frame.f_code.co_filename 96 if os.path.isfile(filename): 97 self.flist.gotofileline(filename, lineno) 98 99class VariablesTreeItem(ObjectTreeItem): 100 101 def GetText(self): 102 return self.labeltext 103 104 def GetLabelText(self): 105 return None 106 107 def IsExpandable(self): 108 return len(self.object) > 0 109 110 def GetSubList(self): 111 sublist = [] 112 for key in self.object.keys(): 113 try: 114 value = self.object[key] 115 except KeyError: 116 continue 117 def setfunction(value, key=key, object=self.object): 118 object[key] = value 119 item = make_objecttreeitem(key + " =", value, setfunction) 120 sublist.append(item) 121 return sublist 122 123 def keys(self): # unused, left for possible 3rd party use 124 return self.object.keys() 125 126def _stack_viewer(parent): # htest # 127 root = tk.Tk() 128 root.title("Test StackViewer") 129 width, height, x, y = list(map(int, re.split('[x+]', parent.geometry()))) 130 root.geometry("+%d+%d"%(x, y + 150)) 131 flist = PyShellFileList(root) 132 try: # to obtain a traceback object 133 intentional_name_error 134 except NameError: 135 exc_type, exc_value, exc_tb = sys.exc_info() 136 137 # inject stack trace to sys 138 sys.last_type = exc_type 139 sys.last_value = exc_value 140 sys.last_traceback = exc_tb 141 142 StackBrowser(root, flist=flist, top=root, tb=exc_tb) 143 144 # restore sys to original state 145 del sys.last_type 146 del sys.last_value 147 del sys.last_traceback 148 149if __name__ == '__main__': 150 from idlelib.idle_test.htest import run 151 run(_stack_viewer) 152