Package flumotion :: Package extern :: Module exceptiondialog
[hide private]

Source Code for Module flumotion.extern.exceptiondialog

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Copyright (C) 2005,2006,2007 by Async Open Source and Sicem S.L. 
  5  #               2008 Fluendo, S.L. (www.fluendo.com). 
  6   
  7  # This program is free software; you can redistribute it and/or 
  8  # modify it under the terms of the GNU Lesser General Public License 
  9  # as published by the Free Software Foundation; either version 2 
 10  # of the License, or (at your option) any later version. 
 11   
 12  # This program is distributed in the hope that it will be useful, 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 15  # GNU General Public License for more details. 
 16   
 17  # You should have received a copy of the GNU Lesser General Public License 
 18  # along with this program; if not, write to the Free Software 
 19  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 20   
 21  # Contains portions originally written by Lorenzo Gil Sanchez and Johan Dahlin 
 22   
 23  # Headers in this file shall remain intact. 
 24   
 25  import gettext 
 26  import linecache 
 27  import os 
 28  import sys 
 29  import traceback 
 30   
 31  import pango 
 32  import gtk 
 33  from kiwi.ui.dialogs import HIGAlertDialog 
 34   
 35  _ = gettext.gettext 
 36   
 37  # FIXME: Get colors from the Gtk+ theme or use tango colors 
 38  FILENAME_COLOR = 'gray20' 
 39  NAME_COLOR = '#000055' 
 40  EXCEPTION_COLOR = '#880000' 
 41   
 42   
43 -class TracebackViewer(gtk.ScrolledWindow):
44
45 - def __init__(self, excTuple):
46 exctype, value, tb = excTuple 47 self._exctype = exctype 48 self._tb = tb 49 self._value = value 50 51 gtk.ScrolledWindow.__init__(self) 52 self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 53 self.set_shadow_type(gtk.SHADOW_ETCHED_IN) 54 self._createUI() 55 self._showException()
56
57 - def _createUI(self):
58 self._buffer = gtk.TextBuffer() 59 self._buffer.create_tag('filename', style=pango.STYLE_ITALIC, 60 foreground=FILENAME_COLOR) 61 self._buffer.create_tag('name', foreground=NAME_COLOR) 62 self._buffer.create_tag('lineno', weight=pango.WEIGHT_BOLD) 63 self._buffer.create_tag('exc', foreground=EXCEPTION_COLOR, 64 weight=pango.WEIGHT_BOLD) 65 66 textView = gtk.TextView(self._buffer) 67 self.add(textView) 68 textView.show()
69
70 - def _print(self, line):
71 self._buffer.insert_at_cursor(line + '\n')
72
73 - def _printFile(self, filename, lineno, name):
74 self._insertText(' File ') 75 self._insertText(filename, 'filename') 76 self._insertText(', line ') 77 self._insertText(str(lineno), 'lineno') 78 self._insertText(', in ') 79 self._insertText(name, 'name') 80 self._insertText('\n')
81
82 - def _insertText(self, text, tagName=None):
83 end_iter = self._buffer.get_end_iter() 84 if tagName: 85 self._buffer.insert_with_tags_by_name(end_iter, text, tagName) 86 else: 87 self._buffer.insert(end_iter, text)
88
89 - def _printTraceback(self):
90 """Print up to 'limit' stack trace entries from the traceback 'tb'. 91 92 If 'limit' is omitted or None, all entries are printed. If 'file' 93 is omitted or None, the output goes to sys.stderr; otherwise 94 'file' should be an open file or file-like object with a write() 95 method. 96 """ 97 98 for tb in self._getTracebacks(): 99 co = tb.tb_frame.f_code 100 self._printFile(co.co_filename, tb.tb_lineno, co.co_name) 101 line = linecache.getline(co.co_filename, tb.tb_lineno) 102 if line: 103 self._print(' ' + line.strip())
104
105 - def _showException(self):
106 widget = gtk.grab_get_current() 107 if widget is not None: 108 widget.grab_remove() 109 110 self._printTraceback() 111 msg = traceback.format_exception_only(self._exctype, self._value)[0] 112 result = msg.split(' ', 1) 113 if len(result) == 1: 114 msg = result[0] 115 arguments = '' 116 else: 117 msg, arguments = result 118 self._insertText(msg, 'exc') 119 self._insertText(' ' + arguments) 120 121 # scroll to end 122 vadj = self.get_vadjustment() 123 vadj.set_value(vadj.upper)
124
125 - def _getTracebacks(self, limit=None):
126 if limit is None: 127 limit = getattr(sys, 'tracebacklimit', None) 128 129 n = 0 130 tb = self._tb 131 while tb is not None: 132 if limit is not None and n >= limit: 133 break 134 n += 1 135 136 yield tb 137 tb = tb.tb_next
138 139 # Public API 140
141 - def getSummary(self):
142 lastFilename = list(self.getFilenames())[-1] 143 filename = os.path.basename(lastFilename) 144 text = self.getDescription() 145 for lastline in text.split('\n')[::-1]: 146 if lastline != '': 147 break 148 return '%s:%d %s' % (filename, self._tb.tb_lineno, lastline)
149
150 - def getDescription(self):
151 return self._buffer.get_text(*self._buffer.get_bounds())
152
153 - def getFilenames(self):
154 cwd = os.getcwd() 155 for tb in self._getTracebacks(): 156 filename = tb.tb_frame.f_code.co_filename 157 if filename.startswith(cwd): 158 filename = filename.replace(cwd, '')[1:] 159 yield filename
160 161
162 -class ExceptionDialog(HIGAlertDialog):
163 """I am a dialog that can display a python exception 164 and code to report a bug. 165 """ 166 RESPONSE_BUG = 1 167
168 - def __init__(self, excTuple):
169 """ 170 @param excTuple: 171 @type excTuple: 172 """ 173 toplevels = gtk.window_list_toplevels() 174 if toplevels: 175 # FIXME: how do we find the topmost one? 176 parent = toplevels[0] 177 else: 178 parent = None 179 HIGAlertDialog.__init__(self, 180 parent=parent, 181 flags=gtk.DIALOG_MODAL, 182 type=gtk.MESSAGE_ERROR, 183 buttons=gtk.BUTTONS_NONE) 184 self.set_primary(_("A programming error occurred.")) 185 self.add_button(_("Report a bug"), ExceptionDialog.RESPONSE_BUG) 186 self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) 187 self.set_default_response(gtk.RESPONSE_CLOSE) 188 189 self._dw = self._createTracebackViewer(excTuple) 190 self.set_details_widget(self._dw) 191 192 # FIXME: Add a kiwi API to set the detail label 193 expander = self._dw.get_parent() 194 expander.set_label(_("Show debug information"))
195
196 - def _createTracebackViewer(self, excTuple):
197 dw = TracebackViewer(excTuple) 198 # How can we make it resize itself sanely depending on the number 199 # of lines it has 200 dw.set_size_request(500, 200) 201 dw.show() 202 return dw
203
204 - def getSummary(self):
205 return self._dw.getSummary()
206
207 - def getDescription(self):
208 return self._dw.getDescription()
209
210 - def getFilenames(self):
211 return self._dw.getFilenames()
212