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