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