Completed
Push — master ( deac0a...381858 )
by Stephan
31s
created

analyse()   F

Complexity

Conditions 21

Size

Total Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 21
c 2
b 0
f 0
dl 0
loc 62
rs 3.0183

1 Method

Rating   Name   Duplication   Size   Complexity  
A readline() 0 7 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like analyse() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""Graphical exception handler for PyGTK applications
2
3
(c) 2003 Gustavo J A M Carneiro gjc at inescporto.pt
4
(c) 2004-2005 Filip Van Raemdonck
5
(c) 2009, 2011, 2017 Stephan Sokolow
6
7
http://www.daa.com.au/pipermail/pygtk/2003-August/005775.html
8
Message-ID: <[email protected]>
9
"The license is whatever you want."
10
11
Instructions: import gtkexcepthook; gtkexcepthook.enable()
12
13
Changes from Van Raemdonck version:
14
 - Switched from auto-enable to gtkexcepthook.enable() to silence PyFlakes
15
   false positives. (Borrowed naming convention from cgitb)
16
 - Split out traceback import to silence PyFlakes warning.
17
 - Started to resolve PyLint complaints
18
19
@todo: Polish this up to meet my code formatting and clarity standards.
20
@todo: Clean up the SMTP support. It's a mess.
21
@todo: Confirm there isn't any other generally-applicable information that
22
       could be included in the debugging dump.
23
@todo: Consider the pros and cons of offering a function which allows
24
       app-specific debugging information to be registered for inclusion.
25
"""
26
27
__author__ = "Filip Van Daemdonck"
28
__license__ = "whatever you want"
29
30
import inspect, linecache, pydoc, sys
31
# import traceback
32
from cStringIO import StringIO
33
from gettext import gettext as _
34
from pprint import pformat
35
from smtplib import SMTP
36
37
import pygtk
38
pygtk.require('2.0')
39
import gtk, pango
40
41
# TODO: Decide what to do with this
42
# def analyse(exctyp, value, tback):
43
#     trace = StringIO()
44
#     traceback.print_exception(exctyp, value, tback, None, trace)
45
#     return trace
46
47
def lookup(name, frame, lcls):
48
    '''Find the value for a given name in the given frame'''
49
    if name in lcls:
50
        return 'local', lcls[name]
51
    elif name in frame.f_globals:
52
        return 'global', frame.f_globals[name]
53
    elif '__builtins__' in frame.f_globals:
54
        builtins = frame.f_globals['__builtins__']
55
        if isinstance(builtins, dict):
56
            if name in builtins:
57
                return 'builtin', builtins[name]
58
        else:
59
            if hasattr(builtins, name):
60
                return 'builtin', getattr(builtins, name)
61
    return None, []
62
63
def analyse(exctyp, value, tback):
64
    import tokenize, keyword
65
66
    trace = StringIO()
67
    nlines = 3
68
    frecs = inspect.getinnerframes(tback, nlines)
69
    trace.write('Traceback (most recent call last):\n')
70
    # pylint: disable=unused-variable
71
    for frame, fname, lineno, funcname, context, cindex in frecs:
72
        trace.write('  File "%s", line %d, ' % (fname, lineno))
73
        args, varargs, varkw, lcls = inspect.getargvalues(frame)
74
75
        def readline(lno=[lineno], *args):
76
            if args:
77
                print args
78
            try:
79
                return linecache.getline(fname, lno[0])
80
            finally:
81
                lno[0] += 1
82
        _all, prev, name, scope = {}, None, '', None
83
        for ttype, tstr, stup, etup, lin in tokenize.generate_tokens(readline):
84
            if ttype == tokenize.NAME and tstr not in keyword.kwlist:
85
                if name:
86
                    if name[-1] == '.':
87
                        try:
88
                            val = getattr(prev, tstr)
89
                        except AttributeError:
90
                            # XXX skip the rest of this identifier only
91
                            break
92
                        name += tstr
93
                else:
94
                    assert not name and not scope
95
                    scope, val = lookup(tstr, frame, lcls)
96
                    name = tstr
97
                try:
98
                    if val:
99
                        prev = val
100
                except:
101
                    pass
102
                # TODO
103
                # print('  found', scope, 'name', name, 'val', val, 'in',
104
                #       prev, 'for token', tstr)
105
            elif tstr == '.':
106
                if prev:
107
                    name += '.'
108
            else:
109
                if name:
110
                    _all[name] = (scope, prev)
111
                prev, name, scope = None, '', None
112
                if ttype == tokenize.NEWLINE:
113
                    break
114
115
        trace.write(funcname +
116
          inspect.formatargvalues(args, varargs, varkw, lcls,
117
            formatvalue=lambda v: '=' + pydoc.text.repr(v)) + '\n')
118
        trace.write(''.join(['    ' + x.replace('\t', '  ')
119
                             for x in context if x.strip()]))
120
        if len(_all):
121
            trace.write('  variables: %s\n' % pformat(_all, indent=3))
122
123
    trace.write('%s: %s' % (exctyp.__name__, value))
124
    return trace
125
126
def _info(exctyp, value, tback):
127
    # pylint: disable=no-member
128
    trace = None
129
    dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
130
                               buttons=gtk.BUTTONS_NONE)
131
    dialog.set_title(_("Bug Detected"))
132
    if gtk.check_version(2, 4, 0) is not None:
133
        dialog.set_has_separator(False)
134
135
    primary = _("<big><b>A programming error has been detected during the "
136
                "execution of this program.</b></big>")
137
    secondary = _("It probably isn't fatal, but should be reported to the "
138
                  "developers nonetheless.")
139
140
    try:
141
        # TODO: Refactor to not use a try/except
142
        email = feedback  # pylint: disable=undefined-variable
143
        dialog.add_button(_("Report..."), 3)
144
    except NameError:
145
        secondary += _("\n\nPlease remember to include the contents of the "
146
                       "Details dialog.")
147
        # could ask for an email address instead...
148
149
    try:
150
        setsec = dialog.format_secondary_text
151
    except AttributeError:
152
        raise
153
        # TODO
154
        # dialog.vbox.get_children()[0].get_children()[1].set_markup(
155
        #    '%s\n\n%s' % (primary, secondary))
156
        # lbl.set_property("use-markup", True)
157
    else:
158
        del setsec
159
        dialog.set_markup(primary)
160
        dialog.format_secondary_text(secondary)
161
162
    dialog.add_button(_("Details..."), 2)
163
    dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
164
    dialog.add_button(gtk.STOCK_QUIT, 1)
165
166
    while True:
167
        resp = dialog.run()
168
        if resp == 3:
169
            if trace is None:
170
                trace = analyse(exctyp, value, tback)
171
172
            # TODO: prettyprint, deal with problems in sending feedback, &tc
173
            # TODO: Refactor to not use a try/except
174
            try:
175
                server = smtphost  # pylint: disable=undefined-variable
176
            except NameError:
177
                server = 'localhost'
178
179
            message = ('From: buggy_application"\nTo: bad_programmer\n'
180
                'Subject: Exception feedback\n\n%s' % trace.getvalue())
181
182
            smtp = SMTP()
183
            smtp.connect(server)
184
            smtp.sendmail(email, (email,), message)
185
            smtp.quit()
186
            break
187
188
        elif resp == 2:
189
            if trace is None:
190
                trace = analyse(exctyp, value, tback)
191
192
            # Show details...
193
            details = gtk.Dialog(_("Bug Details"), dialog,
194
              gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
195
              (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE, ))
196
            details.set_property("has-separator", False)
197
198
            textview = gtk.TextView()
199
            textview.show()
200
            textview.set_editable(False)
201
            textview.modify_font(pango.FontDescription("Monospace"))
202
203
            swin = gtk.ScrolledWindow()
204
            swin.show()
205
            swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
206
            swin.add(textview)
207
            details.vbox.add(swin)
208
            textbuffer = textview.get_buffer()
209
            textbuffer.set_text(trace.getvalue())
210
211
            monitor = gtk.gdk.screen_get_default().get_monitor_at_window(
212
                dialog.window)
213
            area = gtk.gdk.screen_get_default().get_monitor_geometry(monitor)
214
            try:
215
                w = area.width // 1.6
216
                h = area.height // 1.6
217
            except SyntaxError:
218
                # python < 2.2
219
                w = area.width / 1.6
220
                h = area.height / 1.6
221
            details.set_default_size(int(w), int(h))
222
223
            details.run()
224
            details.destroy()
225
226
        elif resp == 1 and gtk.main_level() > 0:
227
            gtk.main_quit()
228
            break
229
        else:
230
            break
231
232
    dialog.destroy()
233
234
def enable():
235
    """Call this to set gtkexcepthook as the default exception handler"""
236
    sys.excepthook = _info
237
238
239
if __name__ == '__main__':
240
    # pylint: disable=W0201,C0103,R0903,C0111
241
    class X(object):
242
        pass
243
    x = X()
244
    x.y = 'Test'
245
    x.z = x
246
    w = ' e'
247
    # TODO: Refactor this
248
    # feedback = '[email protected]'
249
    # smtphost = 'mx.bigcorp.comp'
250
    # 1, x.z.y, f, w
251
    raise Exception(x.z.y + w)
252