1 # Rename to stackbrowser or possibly consolidate with browser.
2
3 import linecache
4 import os
5
6 import tkinter as tk
7
8 from idlelib.debugobj import ObjectTreeItem, make_objecttreeitem
9 from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
10
11 def 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
22 class ESC[4;38;5;81mStackTreeItem(ESC[4;38;5;149mTreeItem):
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
49 class ESC[4;38;5;81mFrameTreeItem(ESC[4;38;5;149mTreeItem):
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
91 class ESC[4;38;5;81mVariablesTreeItem(ESC[4;38;5;149mObjectTreeItem):
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
116 def _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
129 if __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)