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