##// END OF EJS Templates
- Made the internal crash handler very customizable for end-user apps based...
fptest -
Show More
@@ -1,7 +1,7 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 $Id: CrashHandler.py 1326 2006-05-25 02:07:11Z fperez $"""
4 $Id: CrashHandler.py 1828 2006-10-16 02:04:33Z fptest $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
@@ -31,14 +31,90 b' from IPython.genutils import *'
31
31
32 #****************************************************************************
32 #****************************************************************************
33 class CrashHandler:
33 class CrashHandler:
34 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
34 """Customizable crash handlers for IPython-based systems.
35
35
36 def __init__(self,IP):
36 Instances of this class provide a __call__ method which can be used as a
37 sys.excepthook, i.e., the __call__ signature is:
38
39 def __call__(self,etype, evalue, etb)
40
41 """
42
43 def __init__(self,IP,app_name,contact_name,contact_email,
44 bug_tracker,crash_report_fname,
45 show_crash_traceback=True):
46 """New crash handler.
47
48 Inputs:
49
50 - IP: a running IPython instance, which will be queried at crash time
51 for internal information.
52
53 - app_name: a string containing the name of your application.
54
55 - contact_name: a string with the name of the person to contact.
56
57 - contact_email: a string with the email address of the contact.
58
59 - bug_tracker: a string with the URL for your project's bug tracker.
60
61 - crash_report_fname: a string with the filename for the crash report
62 to be saved in. These reports are left in the ipython user directory
63 as determined by the running IPython instance.
64
65 Optional inputs:
66
67 - show_crash_traceback(True): if false, don't print the crash
68 traceback on stderr, only generate the on-disk report
69
70
71 Non-argument instance attributes:
72
73 These instances contain some non-argument attributes which allow for
74 further customization of the crash handler's behavior. Please see the
75 source for further details.
76 """
77
78 # apply args into instance
37 self.IP = IP # IPython instance
79 self.IP = IP # IPython instance
38 self.bug_contact = Release.authors['Ville'][0]
80 self.app_name = app_name
39 self.mailto = Release.authors['Ville'][1]
81 self.contact_name = contact_name
82 self.contact_email = contact_email
83 self.bug_tracker = bug_tracker
84 self.crash_report_fname = crash_report_fname
85 self.show_crash_traceback = show_crash_traceback
86
87 # Hardcoded defaults, which can be overridden either by subclasses or
88 # at runtime for the instance.
89
90 # Template for the user message. Subclasses which completely override
91 # this, or user apps, can modify it to suit their tastes. It gets
92 # expanded using itpl, so calls of the kind $self.foo are valid.
93 self.user_message_template = """
94 Oops, $self.app_name crashed. We do our best to make it stable, but...
95
96 A crash report was automatically generated with the following information:
97 - A verbatim copy of the crash traceback.
98 - A copy of your input history during this session.
99 - Data on your current $self.app_name configuration.
100
101 It was left in the file named:
102 \t'$self.crash_report_fname'
103 If you can email this file to the developers, the information in it will help
104 them in understanding and correcting the problem.
105
106 You can mail it to: $self.contact_name at $self.contact_email
107 with the subject '$self.app_name Crash Report'.
108
109 If you want to do it now, the following command will work (under Unix):
110 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
111
112 To ensure accurate tracking of this issue, please file a report about it at:
113 $self.bug_tracker
114 """
40
115
41 def __call__(self,etype, evalue, etb):
116 def __call__(self,etype, evalue, etb):
117 """Handle an exception, call for compatible with sys.excepthook"""
42
118
43 # Report tracebacks shouldn't use color in general (safer for users)
119 # Report tracebacks shouldn't use color in general (safer for users)
44 color_scheme = 'NoColor'
120 color_scheme = 'NoColor'
@@ -52,60 +128,100 b' class CrashHandler:'
52 rptdir = os.getcwd()
128 rptdir = os.getcwd()
53 if not os.path.isdir(rptdir):
129 if not os.path.isdir(rptdir):
54 rptdir = os.getcwd()
130 rptdir = os.getcwd()
55 self.report_name = os.path.join(rptdir,'IPython_crash_report.txt')
131 report_name = os.path.join(rptdir,self.crash_report_fname)
56 self.TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,long_header=1)
132 # write the report filename into the instance dict so it can get
57 traceback = self.TBhandler.text(etype,evalue,etb,context=31)
133 # properly expanded out in the user message template
134 self.crash_report_fname = report_name
135 TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,
136 long_header=1)
137 traceback = TBhandler.text(etype,evalue,etb,context=31)
58
138
59 # print traceback to screen
139 # print traceback to screen
60 print >> sys.stderr, traceback
140 if self.show_crash_traceback:
141 print >> sys.stderr, traceback
61
142
62 # and generate a complete report on disk
143 # and generate a complete report on disk
63 try:
144 try:
64 report = open(self.report_name,'w')
145 report = open(report_name,'w')
65 except:
146 except:
66 print >> sys.stderr, 'Could not create crash report on disk.'
147 print >> sys.stderr, 'Could not create crash report on disk.'
67 return
148 return
68
149
69 msg = itpl('\n'+'*'*70+'\n'
150 # Inform user on stderr of what happened
70 """
151 msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
71 Oops, IPython crashed. We do our best to make it stable, but...
152 print >> sys.stderr, msg
72
153
73 A crash report was automatically generated with the following information:
154 # Construct report on disk
74 - A verbatim copy of the traceback above this text.
155 report.write(self.make_report(traceback))
75 - A copy of your input history during this session.
156 report.close()
76 - Data on your current IPython configuration.
77
157
78 It was left in the file named:
158 def make_report(self,traceback):
79 \t'$self.report_name'
159 """Return a string containing a crash report."""
80 If you can email this file to the developers, the information in it will help
81 them in understanding and correcting the problem.
82
160
83 You can mail it to $self.bug_contact at $self.mailto
161 sec_sep = '\n\n'+'*'*75+'\n\n'
84 with the subject 'IPython Crash Report'.
85
162
86 If you want to do it now, the following command will work (under Unix):
163 report = []
87 mail -s 'IPython Crash Report' $self.mailto < $self.report_name
164 rpt_add = report.append
165
166 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
167 rpt_add('IPython version: %s \n\n' % Release.version)
168 rpt_add('SVN revision : %s \n\n' % Release.revision)
169 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
170 (os.name,sys.platform) )
171 rpt_add(sec_sep+'Current user configuration structure:\n\n')
172 rpt_add(pformat(self.IP.rc.dict()))
173 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
174 try:
175 rpt_add(sec_sep+"History of session input:")
176 for line in self.IP.user_ns['_ih']:
177 rpt_add(line)
178 rpt_add('\n*** Last line of input (may not be in above history):\n')
179 rpt_add(self.IP._last_input_line+'\n')
180 except:
181 pass
88
182
89 To ensure accurate tracking of this issue, please file a report about it at:
183 return ''.join(report)
90 http://projects.scipy.org/ipython/ipython/report
184
91 """)
185 class IPythonCrashHandler(CrashHandler):
92 print >> sys.stderr, msg
186 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
187
188 def __init__(self,IP):
189
190 # Set here which of the IPython authors should be listed as contact
191 AUTHOR_CONTACT = 'Ville'
192
193 # Set argument defaults
194 app_name = 'IPython'
195 bug_tracker = 'http://projects.scipy.org/ipython/ipython/report'
196 contact_name,contact_email = Release.authors[AUTHOR_CONTACT][:2]
197 crash_report_fname = 'IPython_crash_report.txt'
198 # Call parent constructor
199 CrashHandler.__init__(self,IP,app_name,contact_name,contact_email,
200 bug_tracker,crash_report_fname)
201
202 def make_report(self,traceback):
203 """Return a string containing a crash report."""
93
204
94 sec_sep = '\n\n'+'*'*75+'\n\n'
205 sec_sep = '\n\n'+'*'*75+'\n\n'
95 report.write('*'*75+'\n\n'+'IPython post-mortem report\n\n')
206
96 report.write('IPython version: %s \n\n' % Release.version)
207 report = []
97 report.write('SVN revision : %s \n\n' % Release.revision)
208 rpt_add = report.append
98 report.write('Platform info : os.name -> %s, sys.platform -> %s' %
209
210 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
211 rpt_add('IPython version: %s \n\n' % Release.version)
212 rpt_add('SVN revision : %s \n\n' % Release.revision)
213 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
99 (os.name,sys.platform) )
214 (os.name,sys.platform) )
100 report.write(sec_sep+'Current user configuration structure:\n\n')
215 rpt_add(sec_sep+'Current user configuration structure:\n\n')
101 report.write(pformat(self.IP.rc.dict()))
216 rpt_add(pformat(self.IP.rc.dict()))
102 report.write(sec_sep+'Crash traceback:\n\n' + traceback)
217 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
103 try:
218 try:
104 report.write(sec_sep+"History of session input:")
219 rpt_add(sec_sep+"History of session input:")
105 for line in self.IP.user_ns['_ih']:
220 for line in self.IP.user_ns['_ih']:
106 report.write(line)
221 rpt_add(line)
107 report.write('\n*** Last line of input (may not be in above history):\n')
222 rpt_add('\n*** Last line of input (may not be in above history):\n')
108 report.write(self.IP._last_input_line+'\n')
223 rpt_add(self.IP._last_input_line+'\n')
109 except:
224 except:
110 pass
225 pass
111 report.close()
226
227 return ''.join(report)
@@ -145,6 +145,8 b' class IPApi:'
145
145
146 self.user_ns = ip.user_ns
146 self.user_ns = ip.user_ns
147
147
148 self.set_crash_handler = ip.set_crash_handler
149
148 # Session-specific data store, which can be used to store
150 # Session-specific data store, which can be used to store
149 # data that should persist through the ipython session.
151 # data that should persist through the ipython session.
150 self.meta = ip.meta
152 self.meta = ip.meta
@@ -6,7 +6,7 b' Requires Python 2.3 or newer.'
6
6
7 This file contains all the classes and helper functions specific to IPython.
7 This file contains all the classes and helper functions specific to IPython.
8
8
9 $Id: iplib.py 1822 2006-10-12 21:38:00Z vivainio $
9 $Id: iplib.py 1828 2006-10-16 02:04:33Z fptest $
10 """
10 """
11
11
12 #*****************************************************************************
12 #*****************************************************************************
@@ -543,16 +543,11 b' class InteractiveShell(object,Magic):'
543 # thread (such as in GUI code) propagate directly to sys.excepthook,
543 # thread (such as in GUI code) propagate directly to sys.excepthook,
544 # and there's no point in printing crash dumps for every user exception.
544 # and there's no point in printing crash dumps for every user exception.
545 if self.isthreaded:
545 if self.isthreaded:
546 sys.excepthook = ultraTB.FormattedTB()
546 ipCrashHandler = ultraTB.FormattedTB()
547 else:
547 else:
548 from IPython import CrashHandler
548 from IPython import CrashHandler
549 sys.excepthook = CrashHandler.CrashHandler(self)
549 ipCrashHandler = CrashHandler.IPythonCrashHandler(self)
550
550 self.set_crash_handler(ipCrashHandler)
551 # The instance will store a pointer to this, so that runtime code
552 # (such as magics) can access it. This is because during the
553 # read-eval loop, it gets temporarily overwritten (to deal with GUI
554 # frameworks).
555 self.sys_excepthook = sys.excepthook
556
551
557 # and add any custom exception handlers the user may have specified
552 # and add any custom exception handlers the user may have specified
558 self.set_custom_exc(*custom_exceptions)
553 self.set_custom_exc(*custom_exceptions)
@@ -769,6 +764,22 b' class InteractiveShell(object,Magic):'
769
764
770 #setattr(self.hooks,name,new.instancemethod(hook,self,self.__class__))
765 #setattr(self.hooks,name,new.instancemethod(hook,self,self.__class__))
771
766
767 def set_crash_handler(self,crashHandler):
768 """Set the IPython crash handler.
769
770 This must be a callable with a signature suitable for use as
771 sys.excepthook."""
772
773 # Install the given crash handler as the Python exception hook
774 sys.excepthook = crashHandler
775
776 # The instance will store a pointer to this, so that runtime code
777 # (such as magics) can access it. This is because during the
778 # read-eval loop, it gets temporarily overwritten (to deal with GUI
779 # frameworks).
780 self.sys_excepthook = sys.excepthook
781
782
772 def set_custom_exc(self,exc_tuple,handler):
783 def set_custom_exc(self,exc_tuple,handler):
773 """set_custom_exc(exc_tuple,handler)
784 """set_custom_exc(exc_tuple,handler)
774
785
@@ -1,3 +1,14 b''
1 2006-10-15 Fernando Perez <Fernando.Perez@colorado.edu>
2
3 * IPython/ipapi.py (IPApi.__init__): Added new entry to public
4 api: set_crash_handler(), to expose the ability to change the
5 internal crash handler.
6
7 * IPython/CrashHandler.py (CrashHandler.__init__): abstract out
8 the various parameters of the crash handler so that apps using
9 IPython as their engine can customize crash handling. Ipmlemented
10 at the request of SAGE.
11
1 2006-10-14 Ville Vainio <vivainio@gmail.com>
12 2006-10-14 Ville Vainio <vivainio@gmail.com>
2
13
3 * Magic.py, ipython.el: applied first "safe" part of Rocky
14 * Magic.py, ipython.el: applied first "safe" part of Rocky
General Comments 0
You need to be logged in to leave comments. Login now