jpayne@68: import linecache jpayne@68: import os jpayne@68: import sys jpayne@68: jpayne@68: import tkinter as tk jpayne@68: jpayne@68: from idlelib.debugobj import ObjectTreeItem, make_objecttreeitem jpayne@68: from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas jpayne@68: jpayne@68: def StackBrowser(root, flist=None, tb=None, top=None): jpayne@68: global sc, item, node # For testing. jpayne@68: if top is None: jpayne@68: top = tk.Toplevel(root) jpayne@68: sc = ScrolledCanvas(top, bg="white", highlightthickness=0) jpayne@68: sc.frame.pack(expand=1, fill="both") jpayne@68: item = StackTreeItem(flist, tb) jpayne@68: node = TreeNode(sc.canvas, None, item) jpayne@68: node.expand() jpayne@68: jpayne@68: jpayne@68: class StackTreeItem(TreeItem): jpayne@68: jpayne@68: def __init__(self, flist=None, tb=None): jpayne@68: self.flist = flist jpayne@68: self.stack = self.get_stack(tb) jpayne@68: self.text = self.get_exception() jpayne@68: jpayne@68: def get_stack(self, tb): jpayne@68: if tb is None: jpayne@68: tb = sys.last_traceback jpayne@68: stack = [] jpayne@68: if tb and tb.tb_frame is None: jpayne@68: tb = tb.tb_next jpayne@68: while tb is not None: jpayne@68: stack.append((tb.tb_frame, tb.tb_lineno)) jpayne@68: tb = tb.tb_next jpayne@68: return stack jpayne@68: jpayne@68: def get_exception(self): jpayne@68: type = sys.last_type jpayne@68: value = sys.last_value jpayne@68: if hasattr(type, "__name__"): jpayne@68: type = type.__name__ jpayne@68: s = str(type) jpayne@68: if value is not None: jpayne@68: s = s + ": " + str(value) jpayne@68: return s jpayne@68: jpayne@68: def GetText(self): jpayne@68: return self.text jpayne@68: jpayne@68: def GetSubList(self): jpayne@68: sublist = [] jpayne@68: for info in self.stack: jpayne@68: item = FrameTreeItem(info, self.flist) jpayne@68: sublist.append(item) jpayne@68: return sublist jpayne@68: jpayne@68: jpayne@68: class FrameTreeItem(TreeItem): jpayne@68: jpayne@68: def __init__(self, info, flist): jpayne@68: self.info = info jpayne@68: self.flist = flist jpayne@68: jpayne@68: def GetText(self): jpayne@68: frame, lineno = self.info jpayne@68: try: jpayne@68: modname = frame.f_globals["__name__"] jpayne@68: except: jpayne@68: modname = "?" jpayne@68: code = frame.f_code jpayne@68: filename = code.co_filename jpayne@68: funcname = code.co_name jpayne@68: sourceline = linecache.getline(filename, lineno) jpayne@68: sourceline = sourceline.strip() jpayne@68: if funcname in ("?", "", None): jpayne@68: item = "%s, line %d: %s" % (modname, lineno, sourceline) jpayne@68: else: jpayne@68: item = "%s.%s(...), line %d: %s" % (modname, funcname, jpayne@68: lineno, sourceline) jpayne@68: return item jpayne@68: jpayne@68: def GetSubList(self): jpayne@68: frame, lineno = self.info jpayne@68: sublist = [] jpayne@68: if frame.f_globals is not frame.f_locals: jpayne@68: item = VariablesTreeItem("", frame.f_locals, self.flist) jpayne@68: sublist.append(item) jpayne@68: item = VariablesTreeItem("", frame.f_globals, self.flist) jpayne@68: sublist.append(item) jpayne@68: return sublist jpayne@68: jpayne@68: def OnDoubleClick(self): jpayne@68: if self.flist: jpayne@68: frame, lineno = self.info jpayne@68: filename = frame.f_code.co_filename jpayne@68: if os.path.isfile(filename): jpayne@68: self.flist.gotofileline(filename, lineno) jpayne@68: jpayne@68: jpayne@68: class VariablesTreeItem(ObjectTreeItem): jpayne@68: jpayne@68: def GetText(self): jpayne@68: return self.labeltext jpayne@68: jpayne@68: def GetLabelText(self): jpayne@68: return None jpayne@68: jpayne@68: def IsExpandable(self): jpayne@68: return len(self.object) > 0 jpayne@68: jpayne@68: def GetSubList(self): jpayne@68: sublist = [] jpayne@68: for key in self.object.keys(): jpayne@68: try: jpayne@68: value = self.object[key] jpayne@68: except KeyError: jpayne@68: continue jpayne@68: def setfunction(value, key=key, object=self.object): jpayne@68: object[key] = value jpayne@68: item = make_objecttreeitem(key + " =", value, setfunction) jpayne@68: sublist.append(item) jpayne@68: return sublist jpayne@68: jpayne@68: jpayne@68: def _stack_viewer(parent): # htest # jpayne@68: from idlelib.pyshell import PyShellFileList jpayne@68: top = tk.Toplevel(parent) jpayne@68: top.title("Test StackViewer") jpayne@68: x, y = map(int, parent.geometry().split('+')[1:]) jpayne@68: top.geometry("+%d+%d" % (x + 50, y + 175)) jpayne@68: flist = PyShellFileList(top) jpayne@68: try: # to obtain a traceback object jpayne@68: intentional_name_error jpayne@68: except NameError: jpayne@68: exc_type, exc_value, exc_tb = sys.exc_info() jpayne@68: # inject stack trace to sys jpayne@68: sys.last_type = exc_type jpayne@68: sys.last_value = exc_value jpayne@68: sys.last_traceback = exc_tb jpayne@68: jpayne@68: StackBrowser(top, flist=flist, top=top, tb=exc_tb) jpayne@68: jpayne@68: # restore sys to original state jpayne@68: del sys.last_type jpayne@68: del sys.last_value jpayne@68: del sys.last_traceback jpayne@68: jpayne@68: if __name__ == '__main__': jpayne@68: from unittest import main jpayne@68: main('idlelib.idle_test.test_stackviewer', verbosity=2, exit=False) jpayne@68: jpayne@68: from idlelib.idle_test.htest import run jpayne@68: run(_stack_viewer)