Statistiques
| Révision :

root / ase / gui / gtkexcepthook.py

Historique | Voir | Annoter | Télécharger (6,47 ko)

1 1 tkerber
# vim: sw=4 ts=4:
2 1 tkerber
#
3 1 tkerber
# (c) 2003 Gustavo J A M Carneiro gjc at inescporto.pt
4 1 tkerber
#         2004-2005 Filip Van Raemdonck
5 1 tkerber
#
6 1 tkerber
# http://www.daa.com.au/pipermail/pygtk/2003-August/005775.html
7 1 tkerber
# Message-ID: <1062087716.1196.5.camel@emperor.homelinux.net>
8 1 tkerber
#         "The license is whatever you want."
9 1 tkerber
#
10 1 tkerber
# This file was downloaded from http://www.sysfs.be/downloads/
11 1 tkerber
# Minor adaptions 2009 by Martin Renold:
12 1 tkerber
# - let KeyboardInterrupt through
13 1 tkerber
# - print traceback to stderr before showing the dialog
14 1 tkerber
# - nonzero exit code when hitting the "quit" button
15 1 tkerber
# - suppress more dialogs while one is already active
16 1 tkerber
# see also http://faq.pygtk.org/index.py?req=show&file=faq20.010.htp
17 1 tkerber
# (The license is still whatever you want.)
18 1 tkerber
19 1 tkerber
import inspect, linecache, pydoc, sys, traceback
20 1 tkerber
from cStringIO import StringIO
21 1 tkerber
from gettext import gettext as _
22 1 tkerber
from smtplib import SMTP
23 1 tkerber
24 1 tkerber
import pygtk
25 1 tkerber
pygtk.require ('2.0')
26 1 tkerber
import gtk, pango
27 1 tkerber
28 1 tkerber
def analyse_simple (exctyp, value, tb):
29 1 tkerber
        trace = StringIO()
30 1 tkerber
        traceback.print_exception (exctyp, value, tb, None, trace)
31 1 tkerber
        return trace
32 1 tkerber
33 1 tkerber
def lookup (name, frame, lcls):
34 1 tkerber
        '''Find the value for a given name in the given frame'''
35 1 tkerber
        if name in lcls:
36 1 tkerber
                return 'local', lcls[name]
37 1 tkerber
        elif name in frame.f_globals:
38 1 tkerber
                return 'global', frame.f_globals[name]
39 1 tkerber
        elif '__builtins__' in frame.f_globals:
40 1 tkerber
                builtins = frame.f_globals['__builtins__']
41 1 tkerber
                if type (builtins) is dict:
42 1 tkerber
                        if name in builtins:
43 1 tkerber
                                return 'builtin', builtins[name]
44 1 tkerber
                else:
45 1 tkerber
                        if hasattr (builtins, name):
46 1 tkerber
                                return 'builtin', getattr (builtins, name)
47 1 tkerber
        return None, []
48 1 tkerber
49 1 tkerber
def analyse (exctyp, value, tb):
50 1 tkerber
        import tokenize, keyword
51 1 tkerber
52 1 tkerber
        trace = StringIO()
53 1 tkerber
        nlines = 3
54 1 tkerber
        frecs = inspect.getinnerframes (tb, nlines)
55 1 tkerber
        trace.write ('Traceback (most recent call last):\n')
56 1 tkerber
        for frame, fname, lineno, funcname, context, cindex in frecs:
57 1 tkerber
                trace.write ('  File "%s", line %d, ' % (fname, lineno))
58 1 tkerber
                args, varargs, varkw, lcls = inspect.getargvalues (frame)
59 1 tkerber
60 1 tkerber
                def readline (lno=[lineno], *args):
61 1 tkerber
                        if args: print args
62 1 tkerber
                        try: return linecache.getline (fname, lno[0])
63 1 tkerber
                        finally: lno[0] += 1
64 1 tkerber
                all, prev, name, scope = {}, None, '', None
65 1 tkerber
                for ttype, tstr, stup, etup, line in tokenize.generate_tokens (readline):
66 1 tkerber
                        if ttype == tokenize.NAME and tstr not in keyword.kwlist:
67 1 tkerber
                                if name:
68 1 tkerber
                                        if name[-1] == '.':
69 1 tkerber
                                                try:
70 1 tkerber
                                                        val = getattr (prev, tstr)
71 1 tkerber
                                                except AttributeError:
72 1 tkerber
                                                        # XXX skip the rest of this identifier only
73 1 tkerber
                                                        break
74 1 tkerber
                                                name += tstr
75 1 tkerber
                                else:
76 1 tkerber
                                        assert not name and not scope
77 1 tkerber
                                        scope, val = lookup (tstr, frame, lcls)
78 1 tkerber
                                        name = tstr
79 1 tkerber
                                if hasattr(val, "shape") and len(val):
80 1 tkerber
                                        prev = val
81 1 tkerber
                                elif val:
82 1 tkerber
                                        prev = val
83 1 tkerber
                                #print '  found', scope, 'name', name, 'val', val, 'in', prev, 'for token', tstr
84 1 tkerber
                        elif tstr == '.':
85 1 tkerber
                                if prev:
86 1 tkerber
                                        name += '.'
87 1 tkerber
                        else:
88 1 tkerber
                                if name:
89 1 tkerber
                                        all[name] = (scope, prev)
90 1 tkerber
                                prev, name, scope = None, '', None
91 1 tkerber
                                if ttype == tokenize.NEWLINE:
92 1 tkerber
                                        break
93 1 tkerber
94 1 tkerber
                trace.write (funcname +
95 1 tkerber
                  inspect.formatargvalues (args, varargs, varkw, lcls, formatvalue=lambda v: '=' + pydoc.text.repr (v)) + '\n')
96 1 tkerber
                trace.write (''.join (['    ' + x.replace ('\t', '  ') for x in filter (lambda a: a.strip(), context)]))
97 1 tkerber
                if len (all):
98 1 tkerber
                        trace.write ('  variables: %s\n' % str (all))
99 1 tkerber
100 1 tkerber
        trace.write ('%s: %s' % (exctyp.__name__, value))
101 1 tkerber
        return trace
102 1 tkerber
103 1 tkerber
def _info (exctyp, value, tb):
104 1 tkerber
        global exception_dialog_active
105 1 tkerber
        if exctyp is KeyboardInterrupt:
106 1 tkerber
                return original_excepthook(exctyp, value, tb)
107 1 tkerber
        sys.stderr.write(analyse_simple (exctyp, value, tb).getvalue())
108 1 tkerber
        if exception_dialog_active:
109 1 tkerber
                return
110 1 tkerber
111 1 tkerber
        gtk.gdk.pointer_ungrab()
112 1 tkerber
        gtk.gdk.keyboard_ungrab()
113 1 tkerber
114 1 tkerber
        exception_dialog_active = True
115 1 tkerber
        trace = None
116 1 tkerber
        dialog = gtk.MessageDialog (parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_NONE)
117 1 tkerber
        dialog.set_title (_("Bug Detected"))
118 1 tkerber
        if gtk.check_version (2, 4, 0) is not None:
119 1 tkerber
                dialog.set_has_separator (False)
120 1 tkerber
121 1 tkerber
        primary = _("<big><b>A programming error has been detected.</b></big>")
122 1 tkerber
        secondary = _("It probably isn't fatal, but the details should be reported to the developers nonetheless.")
123 1 tkerber
124 1 tkerber
        try:
125 1 tkerber
                setsec = dialog.format_secondary_text
126 1 tkerber
        except AttributeError:
127 1 tkerber
                raise
128 1 tkerber
                dialog.vbox.get_children()[0].get_children()[1].set_markup ('%s\n\n%s' % (primary, secondary))
129 1 tkerber
                #lbl.set_property ("use-markup", True)
130 1 tkerber
        else:
131 1 tkerber
                del setsec
132 1 tkerber
                dialog.set_markup (primary)
133 1 tkerber
                dialog.format_secondary_text (secondary)
134 1 tkerber
135 1 tkerber
        try:
136 1 tkerber
                email = feedback
137 1 tkerber
                dialog.add_button (_("Report..."), 3)
138 1 tkerber
        except NameError:
139 1 tkerber
                # could ask for an email address instead...
140 1 tkerber
                pass
141 1 tkerber
        dialog.add_button (_("Details..."), 2)
142 1 tkerber
        dialog.add_button (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
143 1 tkerber
        dialog.add_button (gtk.STOCK_QUIT, 1)
144 1 tkerber
145 1 tkerber
        while True:
146 1 tkerber
                resp = dialog.run()
147 1 tkerber
                if resp == 3:
148 1 tkerber
                        if trace == None:
149 1 tkerber
                                trace = analyse (exctyp, value, tb)
150 1 tkerber
151 1 tkerber
                        # TODO: prettyprint, deal with problems in sending feedback, &tc
152 1 tkerber
                        try:
153 1 tkerber
                                server = smtphost
154 1 tkerber
                        except NameError:
155 1 tkerber
                                server = 'localhost'
156 1 tkerber
157 1 tkerber
                        message = 'From: buggy_application"\nTo: bad_programmer\nSubject: Exception feedback\n\n%s' % trace.getvalue()
158 1 tkerber
159 1 tkerber
                        s = SMTP()
160 1 tkerber
                        s.connect (server)
161 1 tkerber
                        s.sendmail (email, (email,), message)
162 1 tkerber
                        s.quit()
163 1 tkerber
                        break
164 1 tkerber
165 1 tkerber
                elif resp == 2:
166 1 tkerber
                        if trace == None:
167 1 tkerber
                                trace = analyse (exctyp, value, tb)
168 1 tkerber
169 1 tkerber
                        # Show details...
170 1 tkerber
                        details = gtk.Dialog (_("Bug Details"), dialog,
171 1 tkerber
                          gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
172 1 tkerber
                          (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE, ))
173 1 tkerber
                        details.set_property ("has-separator", False)
174 1 tkerber
175 1 tkerber
                        textview = gtk.TextView(); textview.show()
176 1 tkerber
                        textview.set_editable (False)
177 1 tkerber
                        textview.modify_font (pango.FontDescription ("Monospace"))
178 1 tkerber
179 1 tkerber
                        sw = gtk.ScrolledWindow(); sw.show()
180 1 tkerber
                        sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
181 1 tkerber
                        sw.add (textview)
182 1 tkerber
                        details.vbox.add (sw)
183 1 tkerber
                        textbuffer = textview.get_buffer()
184 1 tkerber
                        textbuffer.set_text (trace.getvalue())
185 1 tkerber
186 1 tkerber
                        monitor = gtk.gdk.screen_get_default ().get_monitor_at_window (dialog.window)
187 1 tkerber
                        area = gtk.gdk.screen_get_default ().get_monitor_geometry (monitor)
188 1 tkerber
                        try:
189 1 tkerber
                                w = area.width // 1.6
190 1 tkerber
                                h = area.height // 1.6
191 1 tkerber
                        except SyntaxError:
192 1 tkerber
                                # python < 2.2
193 1 tkerber
                                w = area.width / 1.6
194 1 tkerber
                                h = area.height / 1.6
195 1 tkerber
                        details.set_default_size (int (w), int (h))
196 1 tkerber
197 1 tkerber
                        details.run()
198 1 tkerber
                        details.destroy()
199 1 tkerber
200 1 tkerber
                elif resp == 1 and gtk.main_level() > 0:
201 1 tkerber
                        #gtk.main_quit() - why...? Exit code 0 is bad for IDEs.
202 1 tkerber
                        sys.exit(1)
203 1 tkerber
                        break
204 1 tkerber
                else:
205 1 tkerber
                        break
206 1 tkerber
207 1 tkerber
        dialog.destroy()
208 1 tkerber
        exception_dialog_active = False
209 1 tkerber
210 1 tkerber
original_excepthook = sys.excepthook
211 1 tkerber
sys.excepthook = _info
212 1 tkerber
exception_dialog_active = False
213 1 tkerber
214 1 tkerber
if __name__ == '__main__':
215 1 tkerber
        class X (object):
216 1 tkerber
                pass
217 1 tkerber
        x = X()
218 1 tkerber
        x.y = 'Test'
219 1 tkerber
        x.z = x
220 1 tkerber
        w = ' e'
221 1 tkerber
        #feedback = 'developer@bigcorp.comp'
222 1 tkerber
        #smtphost = 'mx.bigcorp.comp'
223 1 tkerber
        1, x.z.y, f, w
224 1 tkerber
        raise Exception (x.z.y + w)