Allow MakeDist to use a specified sf.net account
[rox-lib.git] / python / rox / debug.py
blob324b6c06b7570441b49cd73abb1d6880c64155e1
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
11 savebox = None
13 def _show_debug_help():
14 from os.path import join, dirname
15 help = join(dirname(dirname(dirname(__file__))), 'Help', 'Errors')
16 from rox import filer
17 filer.spawn_rox((help,))
19 def show_exception(type, value, tb, auto_details = False):
20 """Display this exception in an error box. The user has the options
21 of ignoring the error, quitting the application and examining the
22 exception in more detail. See also rox.report_exception()."""
24 QUIT = 1
25 DETAILS = 2
26 SAVE = 3
28 brief = ''.join(traceback.format_exception_only(type, value))
30 toplevel_ref()
31 box = g.MessageDialog(None, 0, g.MESSAGE_ERROR, g.BUTTONS_NONE, brief)
33 if not auto_details:
34 button = ButtonMixed(g.STOCK_ZOOM_IN, _('_Details'))
35 button.set_flags(g.CAN_DEFAULT)
36 button.show()
37 box.add_action_widget(button, DETAILS)
39 box.add_button(g.STOCK_HELP, g.RESPONSE_HELP)
40 box.add_button(g.STOCK_OK, g.RESPONSE_OK)
41 box.set_default_response(g.RESPONSE_OK)
43 box.set_position(g.WIN_POS_CENTER)
44 box.set_title(_('Error'))
45 reply = []
46 def response(box, resp):
47 reply.append(resp)
48 g.main_quit()
49 box.connect('response', response)
50 box.show()
52 bug_report = 'Traceback (most recent call last):\n' + \
53 ''.join(traceback.format_stack(tb.tb_frame.f_back) +
54 traceback.format_tb(tb) +
55 traceback.format_exception_only(type, value))
57 while 1:
58 if auto_details:
59 resp = DETAILS
60 auto_details = False
61 else:
62 g.main()
63 resp = reply.pop()
64 if resp == g.RESPONSE_OK or resp == g.RESPONSE_DELETE_EVENT:
65 break
66 if resp == SAVE:
67 global savebox
68 if savebox:
69 savebox.destroy()
70 def destroy(box):
71 global savebox # For pychecker
72 savebox = None
73 from saving import StringSaver
74 savebox = StringSaver(bug_report, 'BugReport')
75 savebox.connect('destroy', destroy)
76 savebox.show()
77 continue
78 if resp == QUIT:
79 sys.exit(1)
80 elif resp == g.RESPONSE_HELP:
81 _show_debug_help()
82 continue
83 assert resp == DETAILS
84 box.set_response_sensitive(DETAILS, False)
86 button = ButtonMixed(g.STOCK_SAVE, _('_Bug Report'))
87 button.set_flags(g.CAN_DEFAULT)
88 button.show()
89 box.add_action_widget(button, SAVE)
90 box.action_area.set_child_secondary(button, True)
92 button = ButtonMixed(g.STOCK_QUIT, _('Forced Quit'))
93 button.set_flags(g.CAN_DEFAULT)
94 button.show()
95 box.add_action_widget(button, QUIT)
96 box.action_area.set_child_secondary(button, True)
98 ee = ExceptionExplorer(tb)
99 box.vbox.pack_start(ee)
100 ee.show()
101 box.destroy()
102 toplevel_unref()
104 class ExceptionExplorer(g.Frame):
105 """Displays details from a traceback object."""
106 FILE = 0
107 LINE = 1
108 FUNC = 2
109 CODE = 3
110 def __init__(self, tb):
111 g.Frame.__init__(self, _('Stack trace (innermost last)'))
113 vbox = g.VBox(False, 0)
114 self.add(vbox)
116 inner = g.Frame()
117 inner.set_shadow_type(g.SHADOW_IN)
118 vbox.pack_start(inner, False, True, 0)
120 self.savebox = None
122 self.tb = tb
124 self.model = g.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT,
125 gobject.TYPE_STRING, gobject.TYPE_STRING)
126 tree = g.TreeView(self.model)
127 inner.add(tree)
129 cell = g.CellRendererText()
131 column = g.TreeViewColumn('File', cell, text = ExceptionExplorer.FILE)
132 cell.set_property('xalign', 1)
133 tree.append_column(column)
135 cell = g.CellRendererText()
136 column = g.TreeViewColumn('Line', cell, text = ExceptionExplorer.LINE)
137 tree.append_column(column)
138 column = g.TreeViewColumn('Func', cell, text = ExceptionExplorer.FUNC)
139 tree.append_column(column)
140 column = g.TreeViewColumn('Code', cell, text = ExceptionExplorer.CODE)
141 tree.append_column(column)
143 inner.set_border_width(5)
145 frames = []
146 while tb is not None:
147 frames.insert(0, (tb.tb_frame, traceback.tb_lineno(tb)))
148 tb = tb.tb_next
149 f = self.tb.tb_frame
150 if f:
151 f = f.f_back # Skip the reporting frame
152 while f is not None:
153 frames.append((f, f.f_lineno))
154 f = f.f_back
156 frames.reverse()
158 new = None
159 for f, lineno in frames:
160 co = f.f_code
161 filename = co.co_filename
162 name = co.co_name
163 line = linecache.getline(filename, lineno).strip()
165 filename = os.path.basename(filename)
167 new = self.model.append()
168 self.model.set(new, ExceptionExplorer.FILE, filename,
169 ExceptionExplorer.LINE, lineno,
170 ExceptionExplorer.FUNC, name,
171 ExceptionExplorer.CODE, line)
173 def selected_frame():
174 selected = sel.get_selected()
175 assert selected
176 model, titer = selected
177 frame, = model.get_path(titer)
178 return frames[frame][0]
180 vars = g.ListStore(str, str)
181 sel = tree.get_selection()
182 sel.set_mode(g.SELECTION_BROWSE)
183 def select_frame(tree):
184 vars.clear()
185 for n, v in selected_frame().f_locals.iteritems():
186 value = `v`
187 if len(value) > 500:
188 value = value[:500] + ' ...'
189 new = vars.append()
190 vars.set(new, 0, str(n), 1, value)
191 sel.connect('changed', select_frame)
193 # Area to show the local variables
194 tree = g.TreeView(vars)
196 vbox.pack_start(g.Label(_('Local variables in selected frame:')),
197 False, True, 0)
199 cell = g.CellRendererText()
200 column = g.TreeViewColumn('Name', cell, text = 0)
201 cell.set_property('xalign', 1)
202 tree.append_column(column)
203 cell = g.CellRendererText()
204 column = g.TreeViewColumn('Value', cell, text = 1)
205 tree.append_column(column)
207 inner = g.ScrolledWindow()
208 inner.set_size_request(-1, 200)
209 inner.set_policy(g.POLICY_AUTOMATIC, g.POLICY_ALWAYS)
210 inner.set_shadow_type(g.SHADOW_IN)
211 inner.add(tree)
212 inner.set_border_width(5)
213 vbox.pack_start(inner, True, True, 0)
215 if new:
216 sel.select_iter(new)
218 hbox = g.HBox(False, 4)
219 hbox.set_border_width(5)
220 vbox.pack_start(hbox, False, True, 0)
221 hbox.pack_start(g.Label('>>>'), False, True, 0)
223 expr = g.Entry()
224 hbox.pack_start(expr, True, True, 0)
225 def activate(entry):
226 expr = entry.get_text()
227 frame = selected_frame()
228 try:
229 info(`eval(expr, frame.f_locals, frame.f_globals)`)
230 except:
231 extype, value = sys.exc_info()[:2]
232 brief = ''.join(traceback.format_exception_only(extype, value))
233 alert(brief)
234 entry.grab_focus()
235 expr.connect('activate', activate)
237 vbox.show_all()