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 - def __init__(self, excTuple):
45 exctype, value, tb = excTuple 46 self._exctype = exctype 47 self._tb = tb 48 self._value = value 49 50 gtk.ScrolledWindow.__init__(self) 51 self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 52 self.set_shadow_type(gtk.SHADOW_ETCHED_IN) 53 self._createUI() 54 self._showException()
55
56 - def _createUI(self):
57 self._buffer = gtk.TextBuffer() 58 self._buffer.create_tag('filename', style=pango.STYLE_ITALIC, 59 foreground=FILENAME_COLOR) 60 self._buffer.create_tag('name', foreground=NAME_COLOR) 61 self._buffer.create_tag('lineno', weight=pango.WEIGHT_BOLD) 62 self._buffer.create_tag('exc', foreground=EXCEPTION_COLOR, 63 weight=pango.WEIGHT_BOLD) 64 65 textView = gtk.TextView(self._buffer) 66 self.add(textView) 67 textView.show()
68
69 - def _print(self, line):
70 self._buffer.insert_at_cursor(line + '\n')
71
72 - def _printFile(self, filename, lineno, name):
73 self._insertText(' File ') 74 self._insertText(filename, 'filename') 75 self._insertText(', line ') 76 self._insertText(str(lineno), 'lineno') 77 self._insertText(', in ') 78 self._insertText(name, 'name') 79 self._insertText('\n')
80
81 - def _insertText(self, text, tagName=None):
82 end_iter = self._buffer.get_end_iter() 83 if tagName: 84 self._buffer.insert_with_tags_by_name(end_iter, text, tagName) 85 else: 86 self._buffer.insert(end_iter, text)
87
88 - def _printTraceback(self):
89 """Print up to 'limit' stack trace entries from the traceback 'tb'. 90 91 If 'limit' is omitted or None, all entries are printed. If 'file' 92 is omitted or None, the output goes to sys.stderr; otherwise 93 'file' should be an open file or file-like object with a write() 94 method. 95 """ 96 97 for tb in self._getTracebacks(): 98 co = tb.tb_frame.f_code 99 self._printFile(co.co_filename, tb.tb_lineno, co.co_name) 100 line = linecache.getline(co.co_filename, tb.tb_lineno) 101 if line: 102 self._print(' ' + line.strip())
103
104 - def _showException(self):
105 widget = gtk.grab_get_current() 106 if widget is not None: 107 widget.grab_remove() 108 109 self._printTraceback() 110 msg = traceback.format_exception_only(self._exctype, self._value)[0] 111 result = msg.split(' ', 1) 112 if len(result) == 1: 113 msg = result[0] 114 arguments = '' 115 else: 116 msg, arguments = result 117 self._insertText(msg, 'exc') 118 self._insertText(' ' + arguments) 119 120 # scroll to end 121 vadj = self.get_vadjustment() 122 vadj.set_value(vadj.upper)
123
124 - def _getTracebacks(self, limit=None):
125 if limit is None: 126 limit = getattr(sys, 'tracebacklimit', None) 127 128 n = 0 129 tb = self._tb 130 while tb is not None: 131 if limit is not None and n >= limit: 132 break 133 n += 1 134 135 yield tb 136 tb = tb.tb_next
137 138 # Public API 139
140 - def getSummary(self):
141 lastFilename = list(self.getFilenames())[-1] 142 filename = os.path.basename(lastFilename) 143 text = self.getDescription() 144 for lastline in text.split('\n')[::-1]: 145 if lastline != '': 146 break 147 return '%s:%d %s' % (filename, self._tb.tb_lineno, lastline)
148
149 - def getDescription(self):
150 return self._buffer.get_text(*self._buffer.get_bounds())
151
152 - def getFilenames(self):
153 cwd = os.getcwd() 154 for tb in self._getTracebacks(): 155 filename = tb.tb_frame.f_code.co_filename 156 if filename.startswith(cwd): 157 filename = filename.replace(cwd, '')[1:] 158 yield filename
159 160
161 -class ExceptionDialog(HIGAlertDialog):
162 """I am a dialog that can display a python exception 163 and code to report a bug. 164 """ 165 RESPONSE_BUG = 1
166 - def __init__(self, excTuple):
167 """ 168 @param excTuple: 169 @type excTuple: 170 """ 171 toplevels = gtk.window_list_toplevels() 172 if toplevels: 173 # FIXME: how do we find the topmost one? 174 parent = toplevels[0] 175 else: 176 parent = None 177 HIGAlertDialog.__init__(self, 178 parent=parent, 179 flags=gtk.DIALOG_MODAL, 180 type=gtk.MESSAGE_ERROR, 181 buttons=gtk.BUTTONS_NONE) 182 self.set_primary(_("A programming error occurred.")) 183 self.add_button(_("Report a bug"), ExceptionDialog.RESPONSE_BUG) 184 self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) 185 self.set_default_response(gtk.RESPONSE_CLOSE) 186 187 self._dw = self._createTracebackViewer(excTuple) 188 self.set_details_widget(self._dw) 189 190 # FIXME: Add a kiwi API to set the detail label 191 expander = self._dw.get_parent() 192 expander.set_label(_("Show debug information"))
193
194 - def _createTracebackViewer(self, excTuple):
195 dw = TracebackViewer(excTuple) 196 # How can we make it resize itself sanely depending on the number 197 # of lines it has 198 dw.set_size_request(500, 200) 199 dw.show() 200 return dw
201
202 - def getSummary(self):
203 return self._dw.getSummary()
204
205 - def getDescription(self):
206 return self._dw.getDescription()
207
208 - def getFilenames(self):
209 return self._dw.getFilenames()
210