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