##// END OF EJS Templates
Update IPython/core/crashhandler.py
M Bussonnier -
Show More
@@ -1,248 +1,248
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-2011 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 sys
23 23 import traceback
24 24 from pprint import pformat
25 25 from pathlib import Path
26 26
27 27 import builtins as builtin_mod
28 28
29 29 from IPython.core import ultratb
30 30 from IPython.core.application import Application
31 31 from IPython.core.release import author_email
32 32 from IPython.utils.sysinfo import sys_info
33 33
34 34 from IPython.core.release import __version__ as version
35 35
36 36 from typing import Optional, Dict
37 37 import types
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # Code
41 41 #-----------------------------------------------------------------------------
42 42
43 43 # Template for the user message.
44 44 _default_message_template = """\
45 45 Oops, {app_name} crashed. We do our best to make it stable, but...
46 46
47 47 A crash report was automatically generated with the following information:
48 48 - A verbatim copy of the crash traceback.
49 49 - A copy of your input history during this session.
50 50 - Data on your current {app_name} configuration.
51 51
52 52 It was left in the file named:
53 53 \t'{crash_report_fname}'
54 54 If you can email this file to the developers, the information in it will help
55 55 them in understanding and correcting the problem.
56 56
57 57 You can mail it to: {contact_name} at {contact_email}
58 58 with the subject '{app_name} Crash Report'.
59 59
60 60 If you want to do it now, the following command will work (under Unix):
61 61 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
62 62
63 63 In your email, please also include information about:
64 64 - The operating system under which the crash happened: Linux, macOS, Windows,
65 65 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
66 66 Windows 10 Pro), and whether it is 32-bit or 64-bit;
67 67 - How {app_name} was installed: using pip or conda, from GitHub, as part of
68 68 a Docker container, or other, providing more detail if possible;
69 69 - How to reproduce the crash: what exact sequence of instructions can one
70 70 input to get the same crash? Ideally, find a minimal yet complete sequence
71 71 of instructions that yields the crash.
72 72
73 73 To ensure accurate tracking of this issue, please file a report about it at:
74 74 {bug_tracker}
75 75 """
76 76
77 77 _lite_message_template = """
78 78 If you suspect this is an IPython {version} bug, please report it at:
79 79 https://github.com/ipython/ipython/issues
80 80 or send an email to the mailing list at {email}
81 81
82 82 You can print a more detailed traceback right now with "%tb", or use "%debug"
83 83 to interactively debug it.
84 84
85 85 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
86 86 {config}Application.verbose_crash=True
87 87 """
88 88
89 89
90 90 class CrashHandler:
91 91 """Customizable crash handlers for IPython applications.
92 92
93 93 Instances of this class provide a :meth:`__call__` method which can be
94 94 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
95 95
96 96 def __call__(self, etype, evalue, etb)
97 97 """
98 98
99 99 message_template = _default_message_template
100 100 section_sep = '\n\n'+'*'*75+'\n\n'
101 101 info: Dict[str, Optional[str]]
102 102
103 103 def __init__(
104 104 self,
105 105 app: Application,
106 106 contact_name: Optional[str] = None,
107 107 contact_email: Optional[str] = None,
108 108 bug_tracker: Optional[str] = None,
109 109 show_crash_traceback: bool = True,
110 110 call_pdb: bool = False,
111 111 ):
112 112 """Create a new crash handler
113 113
114 114 Parameters
115 115 ----------
116 116 app : Application
117 117 A running :class:`Application` instance, which will be queried at
118 118 crash time for internal information.
119 119 contact_name : str
120 120 A string with the name of the person to contact.
121 121 contact_email : str
122 122 A string with the email address of the contact.
123 123 bug_tracker : str
124 124 A string with the URL for your project's bug tracker.
125 125 show_crash_traceback : bool
126 126 If false, don't print the crash traceback on stderr, only generate
127 127 the on-disk report
128 128 call_pdb
129 129 Whether to call pdb on crash
130 130
131 131 Attributes
132 132 ----------
133 133 These instances contain some non-argument attributes which allow for
134 134 further customization of the crash handler's behavior. Please see the
135 135 source for further details.
136 136
137 137 """
138 138 self.crash_report_fname = "Crash_report_%s.txt" % app.name
139 139 self.app = app
140 140 self.call_pdb = call_pdb
141 141 #self.call_pdb = True # dbg
142 142 self.show_crash_traceback = show_crash_traceback
143 143 self.info = dict(app_name = app.name,
144 144 contact_name = contact_name,
145 145 contact_email = contact_email,
146 146 bug_tracker = bug_tracker,
147 147 crash_report_fname = self.crash_report_fname)
148 148
149 149 def __call__(
150 150 self,
151 151 etype: type[BaseException],
152 152 evalue: BaseException,
153 153 etb: types.TracebackType,
154 154 ) -> None:
155 155 """Handle an exception, call for compatible with sys.excepthook"""
156 156
157 157 # do not allow the crash handler to be called twice without reinstalling it
158 158 # this prevents unlikely errors in the crash handling from entering an
159 159 # infinite loop.
160 160 sys.excepthook = sys.__excepthook__
161 161
162 162 # Report tracebacks shouldn't use color in general (safer for users)
163 163 color_scheme = 'NoColor'
164 164
165 165 # Use this ONLY for developer debugging (keep commented out for release)
166 166 # color_scheme = 'Linux' # dbg
167 ipython_dir = getattr(self.app, "ipython_dir")
167 ipython_dir = getattr(self.app, "ipython_dir", None)
168 168 if ipython_dir is not None:
169 169 assert isinstance(ipython_dir, str)
170 170 rptdir = Path(ipython_dir)
171 171 else:
172 172 rptdir = Path.cwd()
173 173 if not rptdir.is_dir():
174 174 rptdir = Path.cwd()
175 175 report_name = rptdir / self.crash_report_fname
176 176 # write the report filename into the instance dict so it can get
177 177 # properly expanded out in the user message template
178 178 self.crash_report_fname = str(report_name)
179 179 self.info["crash_report_fname"] = str(report_name)
180 180 TBhandler = ultratb.VerboseTB(
181 181 color_scheme=color_scheme,
182 182 long_header=True,
183 183 call_pdb=self.call_pdb,
184 184 )
185 185 if self.call_pdb:
186 186 TBhandler(etype,evalue,etb)
187 187 return
188 188 else:
189 189 traceback = TBhandler.text(etype,evalue,etb,context=31)
190 190
191 191 # print traceback to screen
192 192 if self.show_crash_traceback:
193 193 print(traceback, file=sys.stderr)
194 194
195 195 # and generate a complete report on disk
196 196 try:
197 197 report = open(report_name, "w", encoding="utf-8")
198 198 except:
199 199 print('Could not create crash report on disk.', file=sys.stderr)
200 200 return
201 201
202 202 with report:
203 203 # Inform user on stderr of what happened
204 204 print('\n'+'*'*70+'\n', file=sys.stderr)
205 205 print(self.message_template.format(**self.info), file=sys.stderr)
206 206
207 207 # Construct report on disk
208 208 report.write(self.make_report(str(traceback)))
209 209
210 210 builtin_mod.input("Hit <Enter> to quit (your terminal may close):")
211 211
212 212 def make_report(self, traceback: str) -> str:
213 213 """Return a string containing a crash report."""
214 214
215 215 sec_sep = self.section_sep
216 216
217 217 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
218 218 rpt_add = report.append
219 219 rpt_add(sys_info())
220 220
221 221 try:
222 222 config = pformat(self.app.config)
223 223 rpt_add(sec_sep)
224 224 rpt_add("Application name: %s\n\n" % self.app.name)
225 225 rpt_add("Current user configuration structure:\n\n")
226 226 rpt_add(config)
227 227 except:
228 228 pass
229 229 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
230 230
231 231 return ''.join(report)
232 232
233 233
234 234 def crash_handler_lite(
235 235 etype: type[BaseException], evalue: BaseException, tb: types.TracebackType
236 236 ) -> None:
237 237 """a light excepthook, adding a small message to the usual traceback"""
238 238 traceback.print_exception(etype, evalue, tb)
239 239
240 240 from IPython.core.interactiveshell import InteractiveShell
241 241 if InteractiveShell.initialized():
242 242 # we are in a Shell environment, give %magic example
243 243 config = "%config "
244 244 else:
245 245 # we are not in a shell, show generic config
246 246 config = "c."
247 247 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
248 248
General Comments 0
You need to be logged in to leave comments. Login now