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