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