Viewing file: exception.py (13.24 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#!/usr/bin/python # -*- coding: utf-8 -*- ## Copyright (C) 2001-2005 Red Hat, Inc. ## Copyright (C) 2001-2005 Harald Hoyer <harald@redhat.com>
## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version.
## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details.
## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""Module for a userfriendly exception handling
Example code:
import sys
from rhpl.exception import action, error, exitcode, installExceptionHandler
installExceptionHandler("test", "1.0", gui=0, debug=0)
def exception_function(): action("Trying to divide by zero")
try: local_var_1 = 1 local_var_2 = 0 # test exception raised to show the effect local_var_3 = local_var_1 / local_var_2 except: error("Does not seem to work!? :-)") exitcode(15) raise
if __name__ == '__main__': exception_function() sys.exit(0)
"""
import os, sys from rhpl.translate import _
# # __ExceptionWindow class # class __ExceptionWindow: def __init__ (self, text, component_name): import gtk win = gtk.Dialog(_("Exception Occurred"), None, gtk.DIALOG_MODAL) win.add_button(_("_Debug"), 0) win.add_button(_("_Save to file"), 1) win.add_button(gtk.STOCK_QUIT, 2) win.set_border_width(6) buffer = gtk.TextBuffer(None) buffer.set_text(text) textbox = gtk.TextView() textbox.set_buffer(buffer) textbox.set_property("editable", False) textbox.set_property("cursor_visible", False) sw = gtk.ScrolledWindow () sw.set_shadow_type(gtk.SHADOW_IN) sw.add (textbox) sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) hbox = gtk.HBox (False) hbox.set_border_width(6) txt = _("An unhandled exception has occurred. This " "is most likely a bug. Please save the crash " "dump and file a detailed bug " "report against %s at " "https://bugzilla.redhat.com/bugzilla") % \ component_name info = gtk.Label(txt) info.set_line_wrap(True) hbox.pack_start (sw, True) win.vbox.pack_start (info, False) win.vbox.pack_start (hbox, True) win.vbox.set_border_width(12) win.vbox.set_spacing(12) win.set_size_request (500, 300) win.set_position (gtk.WIN_POS_CENTER) contents = win.get_children()[0] win.show_all () self.window = win self.rc = self.window.run () self.window.destroy()
def quit (self, dialog, button): self.rc = button
def getrc (self): # I did it this way for future expantion # 0 is debug if self.rc == 0: return 1 # 1 is save if self.rc == 1: return 2 # 2 is OK elif self.rc == 2: return 0
__dumpHash = {} # XXX do length limits on obj dumps. def __dumpClass(instance, fd, level=0): import types global __dumpHash # protect from loops if not __dumpHash.has_key(instance): __dumpHash[instance] = None else: fd.write("Already dumped\n") return if (instance.__class__.__dict__.has_key("__str__") or instance.__class__.__dict__.has_key("__repr__")): fd.write("%s\n" % (instance,)) return fd.write("%s instance, containing members:\n" % (instance.__class__.__name__)) pad = ' ' * ((level) * 2) for key, value in instance.__dict__.items(): if type(value) == types.ListType: fd.write("%s%s: [" % (pad, key)) first = 1 for item in value: if not first: fd.write(", ") else: first = 0 if type(item) == types.InstanceType: __dumpClass(item, fd, level + 1) else: fd.write("%s" % (item,)) fd.write("]\n") elif type(value) == types.DictType: fd.write("%s%s: {" % (pad, key)) first = 1 for k, v in value.items(): if not first: fd.write(", ") else: first = 0 if type(k) == types.StringType: fd.write("'%s': " % (k,)) else: fd.write("%s: " % (k,)) if type(v) == types.InstanceType: __dumpClass(v, fd, level + 1) else: fd.write("%s" % (v,)) fd.write("}\n") elif type(value) == types.InstanceType: fd.write("%s%s: " % (pad, key)) __dumpClass(value, fd, level + 1) else: fd.write("%s%s: %s\n" % (pad, key, value))
def __dumpException(out, text, tb): from cPickle import Pickler p = Pickler(out)
out.write(text)
trace = tb while trace.tb_next: trace = trace.tb_next frame = trace.tb_frame out.write ("\nLocal variables in innermost frame:\n") try: for (key, value) in frame.f_locals.items(): out.write ("%s: %s\n" % (key, value)) except: pass
def __exceptionWindow(title, text, name): import gtk #print text win = __ExceptionWindow (text, name) return win.getrc ()
def __generic_error_dialog (message, parent_dialog, message_type=None, widget=None, page=0, broken_widget=None): import gtk if message_type == None: message_type = gtk.MESSAGE_ERROR dialog = gtk.MessageDialog(parent_dialog, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, message_type, gtk.BUTTONS_OK, message) if widget != None: if isinstance (widget, gtk.CList): widget.select_row (page, 0) elif isinstance (widget, gtk.Notebook): widget.set_current_page (page) if broken_widget != None: broken_widget.grab_focus () if isinstance (broken_widget, gtk.Entry): broken_widget.select_region (0, -1)
if parent_dialog: dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT) dialog.set_transient_for(parent_dialog) else: dialog.set_position (gtk.WIN_POS_CENTER)
ret = dialog.run () dialog.destroy() return ret
__action_str = "" def action(what): """Describe what you want to do actually. what - string """ global __action_str __action_str = what
__error_str = "" def error(what): """Describe what went wrong with a userfriendly text. what - string """ global __error_str __error_str = what
__exitcode = 10 def exitcode(num): """The exitcode, with which the exception handling routine should call sys.exit(). num - int(exitcode) """ global __exitcode __exitcode = int(num)
def installExceptionHandler(progname, version, gui = 1, debug = 1): """ Install the exception handling function. progname - the name of the application version - the version of the application gui - display a gtk dialog (0,1) to show the error message debug - show the full traceback (with "Save to file" in GUI) """ sys.excepthook = lambda type, value, tb: handleException((type, value, tb), progname, version, gui, debug) # # handleException function # def handleException((type, value, tb), progname, version, gui = 1, debug = 1): """ The exception handling function.
progname - the name of the application version - the version of the application gui - display a gtk dialog (0,1) to show the error message debug - show the full traceback (with "Save to file" in GUI) """ global __action_str global __error_str global __exitcode if not debug: if not gui: print _("Error: %s: %s") % (__action_str, __error_str) else: import gtk text = _("%s\n\n%s:\n%s") % (progname, __action_str, __error_str) __generic_error_dialog(text, None) sys.exit(__exitcode)
# restore original exception handler sys.excepthook = sys.__excepthook__ import os.path import md5 from string import joinfields import traceback
list = traceback.format_exception (type, value, tb) tblast = traceback.extract_tb(tb, limit=None) if len(tblast): tblast = tblast[len(tblast)-1] extxt = traceback.format_exception_only(type, value) if progname: text = "Component: %s\n" % progname if version: text = text + "Version: %s\n" % version text = text + "Summary: TB" if tblast and len(tblast) > 3: ll = [] ll.extend(tblast[:3]) ll[0] = os.path.basename(tblast[0]) tblast = ll
m = md5.new() ntext = "" for t in tblast: ntext += str(t) + ":" m.update(str(t))
text += str(m.hexdigest())[:8] + " " + ntext text += extxt[0] text += "\n" text += joinfields(list, "")
trace = tb while trace.tb_next: trace = trace.tb_next frame = trace.tb_frame text += ("\nLocal variables in innermost frame:\n") try: for (key, value) in frame.f_locals.items(): text += "%s: %s\n" % (key, value) except: pass
if not gui: print text sys.exit(__exitcode)
import gtk if not debug: __generic_error_dialog(text, None) sys.exit(__exitcode)
while 1: rc = __exceptionWindow (_("Exception Occurred"), text, progname) print text
if rc == 1 and tb: import pdb import signal pdb.post_mortem (tb) os.kill(os.getpid(), signal.SIGKILL) elif not rc: sys.exit(__exitcode) else: d = gtk.FileChooserDialog(_("Specify a file to save the dump"), None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) d.set_default_response(gtk.RESPONSE_OK) rc = d.run() if rc == gtk.RESPONSE_OK: file = d.get_filename() d.destroy() if not file or file=="": file = "/tmp/dump"
try: out = open(file, "w") out.write(text) out.close()
except IOError: __generic_error_dialog(_("Failed to write to file %s.") \ % (file), None) else: __generic_error_dialog( _("The application's state has been successfully\n" "written to the file '%s'.") % (file), None, message_type = "info") sys.exit(__exitcode) else: d.destroy() continue
sys.exit(__exitcode)
if __name__ == '__main__': def __exception_function(): action("Trying to divide by zero") try: local_var_1 = 1 local_var_2 = 0 # test exception raised to show the effect local_var_3 = local_var_1 / local_var_2 except: error("Does not seem to work!? :-)") exitcode(15) raise def __usage(): print """%s [-dgh] [--debug] [--gui] [--help] -d, --debug Show the whole backtrace -g, --gui Display a gtk error dialog
-h, --help Display this message""" % (sys.argv[0])
import sys import getopt debug = 1 gui = 0 installExceptionHandler("test", "1.0", gui, debug)
debug = 0
class BadUsage: pass
try: opts, args = getopt.getopt(sys.argv[1:], "dgh", [ "debug", "help", "gui", ]) for opt, val in opts: if opt == '-d' or opt == '--debug': debug = 1 continue
if opt == '-g' or opt == '--gui': gui = 1 continue
if opt == '-h' or opt == '--help': __usage() sys.exit(0) except (getopt.error, BadUsage): __usage() sys.exit(1) installExceptionHandler("test", "1.0", gui, debug)
__exception_function() sys.exit(0)
__author__ = "Harald Hoyer <harald@redhat.com>"
|