##// END OF EJS Templates
Improve user message in lightweight crash handler.
Fernando Perez -
Show More
@@ -1,211 +1,214 b''
1 1 # encoding: utf-8
2 2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 7 * Brian E. Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 12 # Copyright (C) 2008-2010 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import os
23 23 import sys
24 24 import traceback
25 25 from pprint import pformat
26 26
27 27 from IPython.core import ultratb
28 28 from IPython.core.release import author_email
29 29 from IPython.utils.sysinfo import sys_info
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Code
33 33 #-----------------------------------------------------------------------------
34 34
35 35 # Template for the user message.
36 36 _default_message_template = """\
37 37 Oops, {app_name} crashed. We do our best to make it stable, but...
38 38
39 39 A crash report was automatically generated with the following information:
40 40 - A verbatim copy of the crash traceback.
41 41 - A copy of your input history during this session.
42 42 - Data on your current {app_name} configuration.
43 43
44 44 It was left in the file named:
45 45 \t'{crash_report_fname}'
46 46 If you can email this file to the developers, the information in it will help
47 47 them in understanding and correcting the problem.
48 48
49 49 You can mail it to: {contact_name} at {contact_email}
50 50 with the subject '{app_name} Crash Report'.
51 51
52 52 If you want to do it now, the following command will work (under Unix):
53 53 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
54 54
55 55 To ensure accurate tracking of this issue, please file a report about it at:
56 56 {bug_tracker}
57 57 """
58 58
59 59 _lite_message_template = """
60 60 If you suspect this is an IPython bug, please report it at:
61 61 https://github.com/ipython/ipython/issues
62 62 or send an email to the mailing list at {email}
63 63
64 You can enable a much more verbose traceback with:
64 You can print a more detailed traceback right now with "%tb", or use "%debug"
65 to interactively debug it.
66
67 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
65 68 {config}Application.verbose_crash=True
66 69 """
67 70
68 71
69 72 class CrashHandler(object):
70 73 """Customizable crash handlers for IPython applications.
71 74
72 75 Instances of this class provide a :meth:`__call__` method which can be
73 76 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
74 77
75 78 def __call__(self, etype, evalue, etb)
76 79 """
77 80
78 81 message_template = _default_message_template
79 82 section_sep = '\n\n'+'*'*75+'\n\n'
80 83
81 84 def __init__(self, app, contact_name=None, contact_email=None,
82 85 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
83 86 """Create a new crash handler
84 87
85 88 Parameters
86 89 ----------
87 90 app : Application
88 91 A running :class:`Application` instance, which will be queried at
89 92 crash time for internal information.
90 93
91 94 contact_name : str
92 95 A string with the name of the person to contact.
93 96
94 97 contact_email : str
95 98 A string with the email address of the contact.
96 99
97 100 bug_tracker : str
98 101 A string with the URL for your project's bug tracker.
99 102
100 103 show_crash_traceback : bool
101 104 If false, don't print the crash traceback on stderr, only generate
102 105 the on-disk report
103 106
104 107 Non-argument instance attributes:
105 108
106 109 These instances contain some non-argument attributes which allow for
107 110 further customization of the crash handler's behavior. Please see the
108 111 source for further details.
109 112 """
110 113 self.crash_report_fname = "Crash_report_%s.txt" % app.name
111 114 self.app = app
112 115 self.call_pdb = call_pdb
113 116 #self.call_pdb = True # dbg
114 117 self.show_crash_traceback = show_crash_traceback
115 118 self.info = dict(app_name = app.name,
116 119 contact_name = contact_name,
117 120 contact_email = contact_email,
118 121 bug_tracker = bug_tracker,
119 122 crash_report_fname = self.crash_report_fname)
120 123
121 124
122 125 def __call__(self, etype, evalue, etb):
123 126 """Handle an exception, call for compatible with sys.excepthook"""
124 127
125 128 # do not allow the crash handler to be called twice without reinstalling it
126 129 # this prevents unlikely errors in the crash handling from entering an
127 130 # infinite loop.
128 131 sys.excepthook = sys.__excepthook__
129 132
130 133 # Report tracebacks shouldn't use color in general (safer for users)
131 134 color_scheme = 'NoColor'
132 135
133 136 # Use this ONLY for developer debugging (keep commented out for release)
134 137 #color_scheme = 'Linux' # dbg
135 138 try:
136 139 rptdir = self.app.ipython_dir
137 140 except:
138 141 rptdir = os.getcwdu()
139 142 if rptdir is None or not os.path.isdir(rptdir):
140 143 rptdir = os.getcwdu()
141 144 report_name = os.path.join(rptdir,self.crash_report_fname)
142 145 # write the report filename into the instance dict so it can get
143 146 # properly expanded out in the user message template
144 147 self.crash_report_fname = report_name
145 148 self.info['crash_report_fname'] = report_name
146 149 TBhandler = ultratb.VerboseTB(
147 150 color_scheme=color_scheme,
148 151 long_header=1,
149 152 call_pdb=self.call_pdb,
150 153 )
151 154 if self.call_pdb:
152 155 TBhandler(etype,evalue,etb)
153 156 return
154 157 else:
155 158 traceback = TBhandler.text(etype,evalue,etb,context=31)
156 159
157 160 # print traceback to screen
158 161 if self.show_crash_traceback:
159 162 print >> sys.stderr, traceback
160 163
161 164 # and generate a complete report on disk
162 165 try:
163 166 report = open(report_name,'w')
164 167 except:
165 168 print >> sys.stderr, 'Could not create crash report on disk.'
166 169 return
167 170
168 171 # Inform user on stderr of what happened
169 172 print >> sys.stderr, '\n'+'*'*70+'\n'
170 173 print >> sys.stderr, self.message_template.format(**self.info)
171 174
172 175 # Construct report on disk
173 176 report.write(self.make_report(traceback))
174 177 report.close()
175 178 raw_input("Hit <Enter> to quit (your terminal may close):")
176 179
177 180 def make_report(self,traceback):
178 181 """Return a string containing a crash report."""
179 182
180 183 sec_sep = self.section_sep
181 184
182 185 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
183 186 rpt_add = report.append
184 187 rpt_add(sys_info())
185 188
186 189 try:
187 190 config = pformat(self.app.config)
188 191 rpt_add(sec_sep)
189 192 rpt_add('Application name: %s\n\n' % self.app_name)
190 193 rpt_add('Current user configuration structure:\n\n')
191 194 rpt_add(config)
192 195 except:
193 196 pass
194 197 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
195 198
196 199 return ''.join(report)
197 200
198 201
199 202 def crash_handler_lite(etype, evalue, tb):
200 203 """a light excepthook, adding a small message to the usual traceback"""
201 204 traceback.print_exception(etype, evalue, tb)
202 205
203 206 from IPython.core.interactiveshell import InteractiveShell
204 207 if InteractiveShell.initialized():
205 208 # we are in a Shell environment, give %magic example
206 209 config = "%config "
207 210 else:
208 211 # we are not in a shell, show generic config
209 212 config = "c."
210 213 print >> sys.stderr, _lite_message_template.format(email=author_email, config=config)
211 214
General Comments 0
You need to be logged in to leave comments. Login now