File: gtkexcepthook.py

package info (click to toggle)
python-ase 3.12.0-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 14,192 kB
  • ctags: 8,112
  • sloc: python: 93,375; sh: 99; makefile: 94
file content (216 lines) | stat: -rw-r--r-- 9,435 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
from __future__ import print_function
# vim: sw=4 ts=4:
#
# (c) 2003 Gustavo J A M Carneiro gjc at inescporto.pt
#     2004-2005 Filip Van Raemdonck
#
# http://www.daa.com.au/pipermail/pygtk/2003-August/005775.html
# Message-ID: <1062087716.1196.5.camel@emperor.homelinux.net>
#     "The license is whatever you want."
#
# This file was downloaded from http://www.sysfs.be/downloads/
# Minor adaptions 2009 by Martin Renold:
# - let KeyboardInterrupt through
# - print traceback to stderr before showing the dialog
# - nonzero exit code when hitting the "quit" button
# - suppress more dialogs while one is already active
# see also http://faq.pygtk.org/index.py?req=show&file=faq20.010.htp
# (The license is still whatever you want.)

import inspect, linecache, pydoc, sys, traceback
from StringIO import StringIO
from gettext import gettext as _
from smtplib import SMTP

import pygtk
pygtk.require ('2.0')
import gtk, pango

def analyse_simple (exctyp, value, tb):
        trace = StringIO()
        traceback.print_exception (exctyp, value, tb, None, trace)
        return trace

def lookup (name, frame, lcls):
        '''Find the value for a given name in the given frame'''
        if name in lcls:
                return 'local', lcls[name]
        elif name in frame.f_globals:
                return 'global', frame.f_globals[name]
        elif '__builtins__' in frame.f_globals:
                builtins = frame.f_globals['__builtins__']
                if isinstance(builtins, dict):
                        if name in builtins:
                                return 'builtin', builtins[name]
                else:
                        if hasattr (builtins, name):
                                return 'builtin', getattr (builtins, name)
        return None, []

def analyse (exctyp, value, tb):
        import tokenize, keyword

        trace = StringIO()
        nlines = 3
        frecs = inspect.getinnerframes (tb, nlines)
        trace.write ('Traceback (most recent call last):\n')
        for frame, fname, lineno, funcname, context, cindex in frecs:
                trace.write ('  File "%s", line %d, ' % (fname, lineno))
                args, varargs, varkw, lcls = inspect.getargvalues (frame)

                def readline (lno=[lineno], *args):
                        if args: print(args)
                        try: return linecache.getline (fname, lno[0])
                        finally: lno[0] += 1
                all, prev, name, scope = {}, None, '', None
                for ttype, tstr, stup, etup, line in tokenize.generate_tokens (readline):
                        if ttype == tokenize.NAME and tstr not in keyword.kwlist:
                                if name:
                                        if name[-1] == '.':
                                                try:
                                                        val = getattr (prev, tstr)
                                                except AttributeError:
                                                        # XXX skip the rest of this identifier only
                                                        break
                                                name += tstr
                                else:
                                        assert not name and not scope
                                        scope, val = lookup (tstr, frame, lcls)
                                        name = tstr
                                if hasattr(val, "shape") and len(val):
                                        prev = val
                                elif val:
                                        prev = val
                                #print '  found', scope, 'name', name, 'val', val, 'in', prev, 'for token', tstr
                        elif tstr == '.':
                                if prev:
                                        name += '.'
                        else:
                                if name:
                                        all[name] = (scope, prev)
                                prev, name, scope = None, '', None
                                if ttype == tokenize.NEWLINE:
                                        break

                trace.write (funcname +
                  inspect.formatargvalues (args, varargs, varkw, lcls, formatvalue=lambda v: '=' + pydoc.text.repr (v)) + '\n')
                trace.write (''.join (['    ' + x.replace ('\t', '  ') for x in [a for a in context if a.strip()]]))
                if len (all):
                        trace.write ('  variables: %s\n' % str (all))

        trace.write ('%s: %s' % (exctyp.__name__, value))
        return trace

def _info (exctyp, value, tb):
        global exception_dialog_active
        if exctyp is KeyboardInterrupt:
                return original_excepthook(exctyp, value, tb)
        sys.stderr.write(analyse_simple (exctyp, value, tb).getvalue())
        if exception_dialog_active:
                return

        gtk.gdk.pointer_ungrab()
        gtk.gdk.keyboard_ungrab()

        exception_dialog_active = True
        trace = None
        dialog = gtk.MessageDialog (parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_NONE)
        dialog.set_title(_("Bug Detected"))
        if gtk.check_version (2, 4, 0) is not None:
                dialog.set_has_separator (False)

        primary = "<big><b>%s</b></big>" % _("A programming error has been "
                                             "detected.")
        primary += '\n\n<span color="red">'+str(value)+'</span>'
        secondary = _("It probably isn't fatal, but the details should be "
                      "reported to the developers nonetheless.")

        try:
                setsec = dialog.format_secondary_text
        except AttributeError:
                raise
                dialog.vbox.get_children()[0].get_children()[1].set_markup ('%s\n\n%s' % (primary, secondary))
                #lbl.set_property ("use-markup", True)
        else:
                del setsec
                dialog.set_markup (primary)
                dialog.format_secondary_text (secondary)

        try:
                email = feedback
                dialog.add_button(_("Report..."), 3)
        except NameError:
                # could ask for an email address instead...
                pass
        dialog.add_button (_("Details..."), 2)
        dialog.add_button (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
        dialog.add_button (gtk.STOCK_QUIT, 1)

        while True:
                resp = dialog.run()
                if resp == 3:
                        if trace == None:
                                trace = analyse (exctyp, value, tb)

                        # TODO: prettyprint, deal with problems in sending feedback, &tc
                        try:
                                server = smtphost
                        except NameError:
                                server = 'localhost'

                        message = _('From: buggy_application"\nTo: bad_programmer\nSubject: Exception feedback\n\n%s') % trace.getvalue()

                        s = SMTP()
                        s.connect (server)
                        s.sendmail (email, (email,), message)
                        s.quit()
                        break

                elif resp == 2:
                        if trace == None:
                                trace = analyse (exctyp, value, tb)

                        # Show details...
                        details = gtk.Dialog (_("Bug Details"), dialog,
                          gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                          (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE, ))
                        details.set_property ("has-separator", False)

                        textview = gtk.TextView(); textview.show()
                        textview.set_editable (False)
                        textview.modify_font (pango.FontDescription ("Monospace"))

                        sw = gtk.ScrolledWindow(); sw.show()
                        sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                        sw.add (textview)
                        details.vbox.add (sw)
                        textbuffer = textview.get_buffer()
                        textbuffer.set_text (trace.getvalue())

                        monitor = gtk.gdk.screen_get_default ().get_monitor_at_window (dialog.window)
                        area = gtk.gdk.screen_get_default ().get_monitor_geometry (monitor)
                        try:
                                w = area.width // 1.6
                                h = area.height // 1.6
                        except SyntaxError:
                                # python < 2.2
                                w = area.width / 1.6
                                h = area.height / 1.6
                        details.set_default_size (int (w), int (h))

                        details.run()
                        details.destroy()

                elif resp == 1 and gtk.main_level() > 0:
                        #gtk.main_quit() - why...? Exit code 0 is bad for IDEs.
                        sys.exit(1)
                        break
                else:
                        break

        dialog.destroy()
        exception_dialog_active = False

original_excepthook = sys.excepthook
sys.excepthook = _info
exception_dialog_active = False