Better help for processes.
[rox-lib.git] / python / rox / debug.py
blobabf62f6646742837f27e7714fa4e54b4116dc0b3
1 """This module provides features to help with debugging ROX applications."""
3 import sys, os
4 import traceback
5 import gobject
6 import linecache
8 from rox import g, ButtonMixed, toplevel_ref, toplevel_unref, _
9 from rox import info, alert
10 from saving import StringSaver
12 savebox = None
14 def show_exception(type, value, tb, auto_details = False):
15 """Display this exception in an error box. The user has the options
16 of ignoring the error, quitting the application and examining the
17 exception in more detail. See also rox.report_exception()."""
19 QUIT = 1
20 DETAILS = 2
21 SAVE = 3
23 brief = ''.join(traceback.format_exception_only(type, value))
25 toplevel_ref()
26 box = g.MessageDialog(None, 0, g.MESSAGE_ERROR, g.BUTTONS_NONE, brief)
28 if not auto_details:
29 button = ButtonMixed(g.STOCK_ZOOM_IN, _('_Details'))
30 button.set_flags(g.CAN_DEFAULT)
31 button.show()
32 box.add_action_widget(button, DETAILS)
34 box.add_button(g.STOCK_OK, g.RESPONSE_OK)
35 box.set_default_response(g.RESPONSE_OK)
37 box.set_position(g.WIN_POS_CENTER)
38 box.set_title(_('Error'))
39 reply = []
40 def response(box, resp):
41 reply.append(resp)
42 g.mainquit()
43 box.connect('response', response)
44 box.show()
46 bug_report = 'Traceback (most recent call last):\n' + \
47 ''.join(traceback.format_stack(tb.tb_frame.f_back) +
48 traceback.format_tb(tb) +
49 traceback.format_exception_only(type, value))
51 while 1:
52 if auto_details:
53 resp = DETAILS
54 auto_details = False
55 else:
56 g.mainloop()
57 resp = reply.pop()
58 if resp == g.RESPONSE_OK or resp == g.RESPONSE_DELETE_EVENT:
59 break
60 if resp == SAVE:
61 global savebox
62 if savebox:
63 savebox.destroy()
64 def destroy(box):
65 savebox = None
66 savebox = StringSaver(bug_report, 'BugReport')
67 savebox.connect('destroy', destroy)
68 savebox.show()
69 continue
70 if resp == QUIT:
71 sys.exit(1)
72 assert resp == DETAILS
73 box.set_response_sensitive(DETAILS, False)
74 box.set_has_separator(False)
76 button = ButtonMixed(g.STOCK_SAVE, _('_Bug Report'))
77 button.set_flags(g.CAN_DEFAULT)
78 button.show()
79 box.add_action_widget(button, SAVE)
80 box.action_area.set_child_secondary(button, True)
82 button = ButtonMixed(g.STOCK_QUIT, _('Forced Quit'))
83 button.set_flags(g.CAN_DEFAULT)
84 button.show()
85 box.add_action_widget(button, QUIT)
86 box.action_area.set_child_secondary(button, True)
88 ee = ExceptionExplorer(tb)
89 box.vbox.pack_start(ee)
90 ee.show()
91 box.destroy()
92 toplevel_unref()
94 class ExceptionExplorer(g.Frame):
95 FILE = 0
96 LINE = 1
97 FUNC = 2
98 CODE = 3
99 def __init__(self, tb):
100 g.Frame.__init__(self, _('Stack trace (innermost last)'))
102 vbox = g.VBox(False, 0)
103 self.add(vbox)
105 inner = g.Frame()
106 inner.set_shadow_type(g.SHADOW_IN)
107 vbox.pack_start(inner, False, True, 0)
109 self.savebox = None
111 self.tb = tb
113 self.model = g.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT,
114 gobject.TYPE_STRING, gobject.TYPE_STRING)
115 tree = g.TreeView(self.model)
116 inner.add(tree)
118 cell = g.CellRendererText()
120 column = g.TreeViewColumn('File', cell, text = ExceptionExplorer.FILE)
121 cell.set_property('xalign', 1)
122 tree.append_column(column)
124 cell = g.CellRendererText()
125 column = g.TreeViewColumn('Line', cell, text = ExceptionExplorer.LINE)
126 tree.append_column(column)
127 column = g.TreeViewColumn('Func', cell, text = ExceptionExplorer.FUNC)
128 tree.append_column(column)
129 column = g.TreeViewColumn('Code', cell, text = ExceptionExplorer.CODE)
130 tree.append_column(column)
132 inner.set_border_width(5)
134 frames = []
135 while tb is not None:
136 frames.insert(0, (tb.tb_frame, traceback.tb_lineno(tb)))
137 tb = tb.tb_next
138 f = self.tb.tb_frame
139 if f:
140 f = f.f_back # Skip the reporting frame
141 while f is not None:
142 frames.append((f, f.f_lineno))
143 f = f.f_back
145 frames.reverse()
147 new = None
148 for f, lineno in frames:
149 co = f.f_code
150 filename = co.co_filename
151 name = co.co_name
152 line = linecache.getline(filename, lineno).strip()
154 filename = os.path.basename(filename)
156 new = self.model.append()
157 self.model.set(new, ExceptionExplorer.FILE, filename,
158 ExceptionExplorer.LINE, lineno,
159 ExceptionExplorer.FUNC, name,
160 ExceptionExplorer.CODE, line)
162 def selected_frame():
163 selected = sel.get_selected()
164 assert selected
165 model, iter = selected
166 frame, = model.get_path(iter)
167 return frames[frame][0]
169 vars = g.ListStore(str, str)
170 sel = tree.get_selection()
171 sel.set_mode(g.SELECTION_BROWSE)
172 def select_frame(tree):
173 vars.clear()
174 for n, v in selected_frame().f_locals.iteritems():
175 value = `v`
176 if len(value) > 500:
177 value = value[:500] + ' ...'
178 new = vars.append()
179 vars.set(new, 0, str(n), 1, value)
180 sel.connect('changed', select_frame)
182 # Area to show the local variables
183 tree = g.TreeView(vars)
185 vbox.pack_start(g.Label(_('Local variables in selected frame:')),
186 False, True, 0)
188 cell = g.CellRendererText()
189 column = g.TreeViewColumn('Name', cell, text = 0)
190 cell.set_property('xalign', 1)
191 tree.append_column(column)
192 cell = g.CellRendererText()
193 column = g.TreeViewColumn('Value', cell, text = 1)
194 tree.append_column(column)
196 inner = g.ScrolledWindow()
197 inner.set_size_request(-1, 200)
198 inner.set_policy(g.POLICY_AUTOMATIC, g.POLICY_ALWAYS)
199 inner.set_shadow_type(g.SHADOW_IN)
200 inner.add(tree)
201 inner.set_border_width(5)
202 vbox.pack_start(inner, True, True, 0)
204 if new:
205 sel.select_iter(new)
207 hbox = g.HBox(False, 4)
208 hbox.set_border_width(5)
209 vbox.pack_start(hbox, False, True, 0)
210 hbox.pack_start(g.Label('>>>'), False, True, 0)
212 expr = g.Entry()
213 hbox.pack_start(expr, True, True, 0)
214 def activate(entry):
215 expr = entry.get_text()
216 frame = selected_frame()
217 try:
218 info(`eval(expr, frame.f_locals, frame.f_globals)`)
219 except:
220 type, value = sys.exc_info()[:2]
221 brief = ''.join(traceback.format_exception_only(type, value))
222 alert(brief)
223 entry.grab_focus()
224 expr.connect('activate', activate)
226 vbox.show_all()