• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Rename to stackbrowser or possibly consolidate with browser.
2
3import linecache
4import os
5
6import tkinter as tk
7
8from idlelib.debugobj import ObjectTreeItem, make_objecttreeitem
9from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
10
11def StackBrowser(root, exc, flist=None, top=None):
12    global sc, item, node  # For testing.
13    if top is None:
14        top = tk.Toplevel(root)
15    sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
16    sc.frame.pack(expand=1, fill="both")
17    item = StackTreeItem(exc, flist)
18    node = TreeNode(sc.canvas, None, item)
19    node.expand()
20
21
22class StackTreeItem(TreeItem):
23
24    def __init__(self, exc, flist=None):
25        self.flist = flist
26        self.stack = self.get_stack(None if exc is None else exc.__traceback__)
27        self.text = f"{type(exc).__name__}: {str(exc)}"
28
29    def get_stack(self, tb):
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 GetText(self):  # Titlecase names are overrides.
39        return self.text
40
41    def GetSubList(self):
42        sublist = []
43        for info in self.stack:
44            item = FrameTreeItem(info, self.flist)
45            sublist.append(item)
46        return sublist
47
48
49class FrameTreeItem(TreeItem):
50
51    def __init__(self, info, flist):
52        self.info = info
53        self.flist = flist
54
55    def GetText(self):
56        frame, lineno = self.info
57        try:
58            modname = frame.f_globals["__name__"]
59        except:
60            modname = "?"
61        code = frame.f_code
62        filename = code.co_filename
63        funcname = code.co_name
64        sourceline = linecache.getline(filename, lineno)
65        sourceline = sourceline.strip()
66        if funcname in ("?", "", None):
67            item = "%s, line %d: %s" % (modname, lineno, sourceline)
68        else:
69            item = "%s.%s(...), line %d: %s" % (modname, funcname,
70                                             lineno, sourceline)
71        return item
72
73    def GetSubList(self):
74        frame, lineno = self.info
75        sublist = []
76        if frame.f_globals is not frame.f_locals:
77            item = VariablesTreeItem("<locals>", frame.f_locals, self.flist)
78            sublist.append(item)
79        item = VariablesTreeItem("<globals>", frame.f_globals, self.flist)
80        sublist.append(item)
81        return sublist
82
83    def OnDoubleClick(self):
84        if self.flist:
85            frame, lineno = self.info
86            filename = frame.f_code.co_filename
87            if os.path.isfile(filename):
88                self.flist.gotofileline(filename, lineno)
89
90
91class VariablesTreeItem(ObjectTreeItem):
92
93    def GetText(self):
94        return self.labeltext
95
96    def GetLabelText(self):
97        return None
98
99    def IsExpandable(self):
100        return len(self.object) > 0
101
102    def GetSubList(self):
103        sublist = []
104        for key in self.object.keys():  # self.object not necessarily dict.
105            try:
106                value = self.object[key]
107            except KeyError:
108                continue
109            def setfunction(value, key=key, object_=self.object):
110                object_[key] = value
111            item = make_objecttreeitem(key + " =", value, setfunction)
112            sublist.append(item)
113        return sublist
114
115
116def _stackbrowser(parent):  # htest #
117    from idlelib.pyshell import PyShellFileList
118    top = tk.Toplevel(parent)
119    top.title("Test StackViewer")
120    x, y = map(int, parent.geometry().split('+')[1:])
121    top.geometry("+%d+%d" % (x + 50, y + 175))
122    flist = PyShellFileList(top)
123    try: # to obtain a traceback object
124        intentional_name_error
125    except NameError as e:
126        StackBrowser(top, e, flist=flist, top=top)
127
128
129if __name__ == '__main__':
130    from unittest import main
131    main('idlelib.idle_test.test_stackviewer', verbosity=2, exit=False)
132
133    from idlelib.idle_test.htest import run
134    run(_stackbrowser)
135