##// END OF EJS Templates
- Fix exception name printing for Python 2.5.
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,927 +1,933 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultraTB.py -- Spice up your tracebacks!
3 ultraTB.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultraTB
12 import sys,ultraTB
13 sys.excepthook = ultraTB.ColorTB()
13 sys.excepthook = ultraTB.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultraTB
40 import sys,ultraTB
41 sys.excepthook = ultraTB.VerboseTB()
41 sys.excepthook = ultraTB.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
62
63 $Id: ultraTB.py 2156 2007-03-19 02:32:19Z fperez $"""
63 $Id: ultraTB.py 2419 2007-06-01 07:31:42Z fperez $"""
64
64
65 #*****************************************************************************
65 #*****************************************************************************
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
68 #
68 #
69 # Distributed under the terms of the BSD License. The full license is in
69 # Distributed under the terms of the BSD License. The full license is in
70 # the file COPYING, distributed as part of this software.
70 # the file COPYING, distributed as part of this software.
71 #*****************************************************************************
71 #*****************************************************************************
72
72
73 from IPython import Release
73 from IPython import Release
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
75 Release.authors['Fernando'])
75 Release.authors['Fernando'])
76 __license__ = Release.license
76 __license__ = Release.license
77
77
78 # Required modules
78 # Required modules
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import string
84 import string
85 import sys
85 import sys
86 import time
86 import time
87 import tokenize
87 import tokenize
88 import traceback
88 import traceback
89 import types
89 import types
90
90
91 # IPython's own modules
91 # IPython's own modules
92 # Modified pdb which doesn't damage IPython's readline handling
92 # Modified pdb which doesn't damage IPython's readline handling
93 from IPython import Debugger, PyColorize
93 from IPython import Debugger, PyColorize
94 from IPython.ipstruct import Struct
94 from IPython.ipstruct import Struct
95 from IPython.excolors import ExceptionColors
95 from IPython.excolors import ExceptionColors
96 from IPython.genutils import Term,uniq_stable,error,info
96 from IPython.genutils import Term,uniq_stable,error,info
97
97
98 # Globals
98 # Globals
99 # amount of space to put line numbers before verbose tracebacks
99 # amount of space to put line numbers before verbose tracebacks
100 INDENT_SIZE = 8
100 INDENT_SIZE = 8
101
101
102 # Default color scheme. This is used, for example, by the traceback
102 # Default color scheme. This is used, for example, by the traceback
103 # formatter. When running in an actual IPython instance, the user's rc.colors
103 # formatter. When running in an actual IPython instance, the user's rc.colors
104 # value is used, but havinga module global makes this functionality available
104 # value is used, but havinga module global makes this functionality available
105 # to users of ultraTB who are NOT running inside ipython.
105 # to users of ultraTB who are NOT running inside ipython.
106 DEFAULT_SCHEME = 'NoColor'
106 DEFAULT_SCHEME = 'NoColor'
107
107
108 #---------------------------------------------------------------------------
108 #---------------------------------------------------------------------------
109 # Code begins
109 # Code begins
110
110
111 # Utility functions
111 # Utility functions
112 def inspect_error():
112 def inspect_error():
113 """Print a message about internal inspect errors.
113 """Print a message about internal inspect errors.
114
114
115 These are unfortunately quite common."""
115 These are unfortunately quite common."""
116
116
117 error('Internal Python error in the inspect module.\n'
117 error('Internal Python error in the inspect module.\n'
118 'Below is the traceback from this internal error.\n')
118 'Below is the traceback from this internal error.\n')
119
119
120 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
120 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
121 import linecache
121 import linecache
122 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
122 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
123
123
124 records = inspect.getinnerframes(etb, context)
124 records = inspect.getinnerframes(etb, context)
125
125
126 # If the error is at the console, don't build any context, since it would
126 # If the error is at the console, don't build any context, since it would
127 # otherwise produce 5 blank lines printed out (there is no file at the
127 # otherwise produce 5 blank lines printed out (there is no file at the
128 # console)
128 # console)
129 rec_check = records[tb_offset:]
129 rec_check = records[tb_offset:]
130 try:
130 try:
131 rname = rec_check[0][1]
131 rname = rec_check[0][1]
132 if rname == '<ipython console>' or rname.endswith('<string>'):
132 if rname == '<ipython console>' or rname.endswith('<string>'):
133 return rec_check
133 return rec_check
134 except IndexError:
134 except IndexError:
135 pass
135 pass
136
136
137 aux = traceback.extract_tb(etb)
137 aux = traceback.extract_tb(etb)
138 assert len(records) == len(aux)
138 assert len(records) == len(aux)
139 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
139 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
140 maybeStart = lnum-1 - context//2
140 maybeStart = lnum-1 - context//2
141 start = max(maybeStart, 0)
141 start = max(maybeStart, 0)
142 end = start + context
142 end = start + context
143 lines = linecache.getlines(file)[start:end]
143 lines = linecache.getlines(file)[start:end]
144 # pad with empty lines if necessary
144 # pad with empty lines if necessary
145 if maybeStart < 0:
145 if maybeStart < 0:
146 lines = (['\n'] * -maybeStart) + lines
146 lines = (['\n'] * -maybeStart) + lines
147 if len(lines) < context:
147 if len(lines) < context:
148 lines += ['\n'] * (context - len(lines))
148 lines += ['\n'] * (context - len(lines))
149 buf = list(records[i])
149 buf = list(records[i])
150 buf[LNUM_POS] = lnum
150 buf[LNUM_POS] = lnum
151 buf[INDEX_POS] = lnum - 1 - start
151 buf[INDEX_POS] = lnum - 1 - start
152 buf[LINES_POS] = lines
152 buf[LINES_POS] = lines
153 records[i] = tuple(buf)
153 records[i] = tuple(buf)
154 return records[tb_offset:]
154 return records[tb_offset:]
155
155
156 # Helper function -- largely belongs to VerboseTB, but we need the same
156 # Helper function -- largely belongs to VerboseTB, but we need the same
157 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
157 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
158 # can be recognized properly by ipython.el's py-traceback-line-re
158 # can be recognized properly by ipython.el's py-traceback-line-re
159 # (SyntaxErrors have to be treated specially because they have no traceback)
159 # (SyntaxErrors have to be treated specially because they have no traceback)
160
160
161 _parser = PyColorize.Parser()
161 _parser = PyColorize.Parser()
162
162
163 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
163 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
164 numbers_width = INDENT_SIZE - 1
164 numbers_width = INDENT_SIZE - 1
165 res = []
165 res = []
166 i = lnum - index
166 i = lnum - index
167
167
168 # This lets us get fully syntax-highlighted tracebacks.
168 # This lets us get fully syntax-highlighted tracebacks.
169 if scheme is None:
169 if scheme is None:
170 try:
170 try:
171 scheme = __IPYTHON__.rc.colors
171 scheme = __IPYTHON__.rc.colors
172 except:
172 except:
173 scheme = DEFAULT_SCHEME
173 scheme = DEFAULT_SCHEME
174 _line_format = _parser.format2
174 _line_format = _parser.format2
175
175
176 for line in lines:
176 for line in lines:
177 new_line, err = _line_format(line,'str',scheme)
177 new_line, err = _line_format(line,'str',scheme)
178 if not err: line = new_line
178 if not err: line = new_line
179
179
180 if i == lnum:
180 if i == lnum:
181 # This is the line with the error
181 # This is the line with the error
182 pad = numbers_width - len(str(i))
182 pad = numbers_width - len(str(i))
183 if pad >= 3:
183 if pad >= 3:
184 marker = '-'*(pad-3) + '-> '
184 marker = '-'*(pad-3) + '-> '
185 elif pad == 2:
185 elif pad == 2:
186 marker = '> '
186 marker = '> '
187 elif pad == 1:
187 elif pad == 1:
188 marker = '>'
188 marker = '>'
189 else:
189 else:
190 marker = ''
190 marker = ''
191 num = marker + str(i)
191 num = marker + str(i)
192 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
192 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
193 Colors.line, line, Colors.Normal)
193 Colors.line, line, Colors.Normal)
194 else:
194 else:
195 num = '%*s' % (numbers_width,i)
195 num = '%*s' % (numbers_width,i)
196 line = '%s%s%s %s' %(Colors.lineno, num,
196 line = '%s%s%s %s' %(Colors.lineno, num,
197 Colors.Normal, line)
197 Colors.Normal, line)
198
198
199 res.append(line)
199 res.append(line)
200 if lvals and i == lnum:
200 if lvals and i == lnum:
201 res.append(lvals + '\n')
201 res.append(lvals + '\n')
202 i = i + 1
202 i = i + 1
203 return res
203 return res
204
204
205
205
206 #---------------------------------------------------------------------------
206 #---------------------------------------------------------------------------
207 # Module classes
207 # Module classes
208 class TBTools:
208 class TBTools:
209 """Basic tools used by all traceback printer classes."""
209 """Basic tools used by all traceback printer classes."""
210
210
211 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
211 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
212 # Whether to call the interactive pdb debugger after printing
212 # Whether to call the interactive pdb debugger after printing
213 # tracebacks or not
213 # tracebacks or not
214 self.call_pdb = call_pdb
214 self.call_pdb = call_pdb
215
215
216 # Create color table
216 # Create color table
217 self.color_scheme_table = ExceptionColors
217 self.color_scheme_table = ExceptionColors
218
218
219 self.set_colors(color_scheme)
219 self.set_colors(color_scheme)
220 self.old_scheme = color_scheme # save initial value for toggles
220 self.old_scheme = color_scheme # save initial value for toggles
221
221
222 if call_pdb:
222 if call_pdb:
223 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
223 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
224 else:
224 else:
225 self.pdb = None
225 self.pdb = None
226
226
227 def set_colors(self,*args,**kw):
227 def set_colors(self,*args,**kw):
228 """Shorthand access to the color table scheme selector method."""
228 """Shorthand access to the color table scheme selector method."""
229
229
230 # Set own color table
230 # Set own color table
231 self.color_scheme_table.set_active_scheme(*args,**kw)
231 self.color_scheme_table.set_active_scheme(*args,**kw)
232 # for convenience, set Colors to the active scheme
232 # for convenience, set Colors to the active scheme
233 self.Colors = self.color_scheme_table.active_colors
233 self.Colors = self.color_scheme_table.active_colors
234 # Also set colors of debugger
234 # Also set colors of debugger
235 if hasattr(self,'pdb') and self.pdb is not None:
235 if hasattr(self,'pdb') and self.pdb is not None:
236 self.pdb.set_colors(*args,**kw)
236 self.pdb.set_colors(*args,**kw)
237
237
238 def color_toggle(self):
238 def color_toggle(self):
239 """Toggle between the currently active color scheme and NoColor."""
239 """Toggle between the currently active color scheme and NoColor."""
240
240
241 if self.color_scheme_table.active_scheme_name == 'NoColor':
241 if self.color_scheme_table.active_scheme_name == 'NoColor':
242 self.color_scheme_table.set_active_scheme(self.old_scheme)
242 self.color_scheme_table.set_active_scheme(self.old_scheme)
243 self.Colors = self.color_scheme_table.active_colors
243 self.Colors = self.color_scheme_table.active_colors
244 else:
244 else:
245 self.old_scheme = self.color_scheme_table.active_scheme_name
245 self.old_scheme = self.color_scheme_table.active_scheme_name
246 self.color_scheme_table.set_active_scheme('NoColor')
246 self.color_scheme_table.set_active_scheme('NoColor')
247 self.Colors = self.color_scheme_table.active_colors
247 self.Colors = self.color_scheme_table.active_colors
248
248
249 #---------------------------------------------------------------------------
249 #---------------------------------------------------------------------------
250 class ListTB(TBTools):
250 class ListTB(TBTools):
251 """Print traceback information from a traceback list, with optional color.
251 """Print traceback information from a traceback list, with optional color.
252
252
253 Calling: requires 3 arguments:
253 Calling: requires 3 arguments:
254 (etype, evalue, elist)
254 (etype, evalue, elist)
255 as would be obtained by:
255 as would be obtained by:
256 etype, evalue, tb = sys.exc_info()
256 etype, evalue, tb = sys.exc_info()
257 if tb:
257 if tb:
258 elist = traceback.extract_tb(tb)
258 elist = traceback.extract_tb(tb)
259 else:
259 else:
260 elist = None
260 elist = None
261
261
262 It can thus be used by programs which need to process the traceback before
262 It can thus be used by programs which need to process the traceback before
263 printing (such as console replacements based on the code module from the
263 printing (such as console replacements based on the code module from the
264 standard library).
264 standard library).
265
265
266 Because they are meant to be called without a full traceback (only a
266 Because they are meant to be called without a full traceback (only a
267 list), instances of this class can't call the interactive pdb debugger."""
267 list), instances of this class can't call the interactive pdb debugger."""
268
268
269 def __init__(self,color_scheme = 'NoColor'):
269 def __init__(self,color_scheme = 'NoColor'):
270 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
270 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
271
271
272 def __call__(self, etype, value, elist):
272 def __call__(self, etype, value, elist):
273 Term.cout.flush()
273 Term.cout.flush()
274 Term.cerr.flush()
274 Term.cerr.flush()
275 print >> Term.cerr, self.text(etype,value,elist)
275 print >> Term.cerr, self.text(etype,value,elist)
276
276
277 def text(self,etype, value, elist,context=5):
277 def text(self,etype, value, elist,context=5):
278 """Return a color formatted string with the traceback info."""
278 """Return a color formatted string with the traceback info."""
279
279
280 Colors = self.Colors
280 Colors = self.Colors
281 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
281 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
282 if elist:
282 if elist:
283 out_string.append('Traceback %s(most recent call last)%s:' % \
283 out_string.append('Traceback %s(most recent call last)%s:' % \
284 (Colors.normalEm, Colors.Normal) + '\n')
284 (Colors.normalEm, Colors.Normal) + '\n')
285 out_string.extend(self._format_list(elist))
285 out_string.extend(self._format_list(elist))
286 lines = self._format_exception_only(etype, value)
286 lines = self._format_exception_only(etype, value)
287 for line in lines[:-1]:
287 for line in lines[:-1]:
288 out_string.append(" "+line)
288 out_string.append(" "+line)
289 out_string.append(lines[-1])
289 out_string.append(lines[-1])
290 return ''.join(out_string)
290 return ''.join(out_string)
291
291
292 def _format_list(self, extracted_list):
292 def _format_list(self, extracted_list):
293 """Format a list of traceback entry tuples for printing.
293 """Format a list of traceback entry tuples for printing.
294
294
295 Given a list of tuples as returned by extract_tb() or
295 Given a list of tuples as returned by extract_tb() or
296 extract_stack(), return a list of strings ready for printing.
296 extract_stack(), return a list of strings ready for printing.
297 Each string in the resulting list corresponds to the item with the
297 Each string in the resulting list corresponds to the item with the
298 same index in the argument list. Each string ends in a newline;
298 same index in the argument list. Each string ends in a newline;
299 the strings may contain internal newlines as well, for those items
299 the strings may contain internal newlines as well, for those items
300 whose source text line is not None.
300 whose source text line is not None.
301
301
302 Lifted almost verbatim from traceback.py
302 Lifted almost verbatim from traceback.py
303 """
303 """
304
304
305 Colors = self.Colors
305 Colors = self.Colors
306 list = []
306 list = []
307 for filename, lineno, name, line in extracted_list[:-1]:
307 for filename, lineno, name, line in extracted_list[:-1]:
308 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
308 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
309 (Colors.filename, filename, Colors.Normal,
309 (Colors.filename, filename, Colors.Normal,
310 Colors.lineno, lineno, Colors.Normal,
310 Colors.lineno, lineno, Colors.Normal,
311 Colors.name, name, Colors.Normal)
311 Colors.name, name, Colors.Normal)
312 if line:
312 if line:
313 item = item + ' %s\n' % line.strip()
313 item = item + ' %s\n' % line.strip()
314 list.append(item)
314 list.append(item)
315 # Emphasize the last entry
315 # Emphasize the last entry
316 filename, lineno, name, line = extracted_list[-1]
316 filename, lineno, name, line = extracted_list[-1]
317 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
317 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
318 (Colors.normalEm,
318 (Colors.normalEm,
319 Colors.filenameEm, filename, Colors.normalEm,
319 Colors.filenameEm, filename, Colors.normalEm,
320 Colors.linenoEm, lineno, Colors.normalEm,
320 Colors.linenoEm, lineno, Colors.normalEm,
321 Colors.nameEm, name, Colors.normalEm,
321 Colors.nameEm, name, Colors.normalEm,
322 Colors.Normal)
322 Colors.Normal)
323 if line:
323 if line:
324 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
324 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
325 Colors.Normal)
325 Colors.Normal)
326 list.append(item)
326 list.append(item)
327 return list
327 return list
328
328
329 def _format_exception_only(self, etype, value):
329 def _format_exception_only(self, etype, value):
330 """Format the exception part of a traceback.
330 """Format the exception part of a traceback.
331
331
332 The arguments are the exception type and value such as given by
332 The arguments are the exception type and value such as given by
333 sys.exc_info()[:2]. The return value is a list of strings, each ending
333 sys.exc_info()[:2]. The return value is a list of strings, each ending
334 in a newline. Normally, the list contains a single string; however,
334 in a newline. Normally, the list contains a single string; however,
335 for SyntaxError exceptions, it contains several lines that (when
335 for SyntaxError exceptions, it contains several lines that (when
336 printed) display detailed information about where the syntax error
336 printed) display detailed information about where the syntax error
337 occurred. The message indicating which exception occurred is the
337 occurred. The message indicating which exception occurred is the
338 always last string in the list.
338 always last string in the list.
339
339
340 Also lifted nearly verbatim from traceback.py
340 Also lifted nearly verbatim from traceback.py
341 """
341 """
342
342
343 Colors = self.Colors
343 Colors = self.Colors
344 list = []
344 list = []
345 if type(etype) == types.ClassType:
345 try:
346 stype = Colors.excName + etype.__name__ + Colors.Normal
346 stype = Colors.excName + etype.__name__ + Colors.Normal
347 else:
347 except AttributeError:
348 stype = etype # String exceptions don't get special coloring
348 stype = etype # String exceptions don't get special coloring
349 if value is None:
349 if value is None:
350 list.append( str(stype) + '\n')
350 list.append( str(stype) + '\n')
351 else:
351 else:
352 if etype is SyntaxError:
352 if etype is SyntaxError:
353 try:
353 try:
354 msg, (filename, lineno, offset, line) = value
354 msg, (filename, lineno, offset, line) = value
355 except:
355 except:
356 pass
356 pass
357 else:
357 else:
358 #print 'filename is',filename # dbg
358 #print 'filename is',filename # dbg
359 if not filename: filename = "<string>"
359 if not filename: filename = "<string>"
360 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
360 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
361 (Colors.normalEm,
361 (Colors.normalEm,
362 Colors.filenameEm, filename, Colors.normalEm,
362 Colors.filenameEm, filename, Colors.normalEm,
363 Colors.linenoEm, lineno, Colors.Normal ))
363 Colors.linenoEm, lineno, Colors.Normal ))
364 if line is not None:
364 if line is not None:
365 i = 0
365 i = 0
366 while i < len(line) and line[i].isspace():
366 while i < len(line) and line[i].isspace():
367 i = i+1
367 i = i+1
368 list.append('%s %s%s\n' % (Colors.line,
368 list.append('%s %s%s\n' % (Colors.line,
369 line.strip(),
369 line.strip(),
370 Colors.Normal))
370 Colors.Normal))
371 if offset is not None:
371 if offset is not None:
372 s = ' '
372 s = ' '
373 for c in line[i:offset-1]:
373 for c in line[i:offset-1]:
374 if c.isspace():
374 if c.isspace():
375 s = s + c
375 s = s + c
376 else:
376 else:
377 s = s + ' '
377 s = s + ' '
378 list.append('%s%s^%s\n' % (Colors.caret, s,
378 list.append('%s%s^%s\n' % (Colors.caret, s,
379 Colors.Normal) )
379 Colors.Normal) )
380 value = msg
380 value = msg
381 s = self._some_str(value)
381 s = self._some_str(value)
382 if s:
382 if s:
383 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
383 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
384 Colors.Normal, s))
384 Colors.Normal, s))
385 else:
385 else:
386 list.append('%s\n' % str(stype))
386 list.append('%s\n' % str(stype))
387 return list
387 return list
388
388
389 def _some_str(self, value):
389 def _some_str(self, value):
390 # Lifted from traceback.py
390 # Lifted from traceback.py
391 try:
391 try:
392 return str(value)
392 return str(value)
393 except:
393 except:
394 return '<unprintable %s object>' % type(value).__name__
394 return '<unprintable %s object>' % type(value).__name__
395
395
396 #----------------------------------------------------------------------------
396 #----------------------------------------------------------------------------
397 class VerboseTB(TBTools):
397 class VerboseTB(TBTools):
398 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
398 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
399 of HTML. Requires inspect and pydoc. Crazy, man.
399 of HTML. Requires inspect and pydoc. Crazy, man.
400
400
401 Modified version which optionally strips the topmost entries from the
401 Modified version which optionally strips the topmost entries from the
402 traceback, to be used with alternate interpreters (because their own code
402 traceback, to be used with alternate interpreters (because their own code
403 would appear in the traceback)."""
403 would appear in the traceback)."""
404
404
405 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
405 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
406 call_pdb = 0, include_vars=1):
406 call_pdb = 0, include_vars=1):
407 """Specify traceback offset, headers and color scheme.
407 """Specify traceback offset, headers and color scheme.
408
408
409 Define how many frames to drop from the tracebacks. Calling it with
409 Define how many frames to drop from the tracebacks. Calling it with
410 tb_offset=1 allows use of this handler in interpreters which will have
410 tb_offset=1 allows use of this handler in interpreters which will have
411 their own code at the top of the traceback (VerboseTB will first
411 their own code at the top of the traceback (VerboseTB will first
412 remove that frame before printing the traceback info)."""
412 remove that frame before printing the traceback info)."""
413 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
413 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
414 self.tb_offset = tb_offset
414 self.tb_offset = tb_offset
415 self.long_header = long_header
415 self.long_header = long_header
416 self.include_vars = include_vars
416 self.include_vars = include_vars
417
417
418 def text(self, etype, evalue, etb, context=5):
418 def text(self, etype, evalue, etb, context=5):
419 """Return a nice text document describing the traceback."""
419 """Return a nice text document describing the traceback."""
420
420
421 # some locals
421 # some locals
422 try:
423 etype = etype.__name__
424 except AttributeError:
425 pass
422 Colors = self.Colors # just a shorthand + quicker name lookup
426 Colors = self.Colors # just a shorthand + quicker name lookup
423 ColorsNormal = Colors.Normal # used a lot
427 ColorsNormal = Colors.Normal # used a lot
424 col_scheme = self.color_scheme_table.active_scheme_name
428 col_scheme = self.color_scheme_table.active_scheme_name
425 indent = ' '*INDENT_SIZE
429 indent = ' '*INDENT_SIZE
426 exc = '%s%s%s' % (Colors.excName, str(etype), ColorsNormal)
427 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
430 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
428 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
431 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
432 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
429
433
430 # some internal-use functions
434 # some internal-use functions
431 def text_repr(value):
435 def text_repr(value):
432 """Hopefully pretty robust repr equivalent."""
436 """Hopefully pretty robust repr equivalent."""
433 # this is pretty horrible but should always return *something*
437 # this is pretty horrible but should always return *something*
434 try:
438 try:
435 return pydoc.text.repr(value)
439 return pydoc.text.repr(value)
436 except KeyboardInterrupt:
440 except KeyboardInterrupt:
437 raise
441 raise
438 except:
442 except:
439 try:
443 try:
440 return repr(value)
444 return repr(value)
441 except KeyboardInterrupt:
445 except KeyboardInterrupt:
442 raise
446 raise
443 except:
447 except:
444 try:
448 try:
445 # all still in an except block so we catch
449 # all still in an except block so we catch
446 # getattr raising
450 # getattr raising
447 name = getattr(value, '__name__', None)
451 name = getattr(value, '__name__', None)
448 if name:
452 if name:
449 # ick, recursion
453 # ick, recursion
450 return text_repr(name)
454 return text_repr(name)
451 klass = getattr(value, '__class__', None)
455 klass = getattr(value, '__class__', None)
452 if klass:
456 if klass:
453 return '%s instance' % text_repr(klass)
457 return '%s instance' % text_repr(klass)
454 except KeyboardInterrupt:
458 except KeyboardInterrupt:
455 raise
459 raise
456 except:
460 except:
457 return 'UNRECOVERABLE REPR FAILURE'
461 return 'UNRECOVERABLE REPR FAILURE'
458 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
462 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
459 def nullrepr(value, repr=text_repr): return ''
463 def nullrepr(value, repr=text_repr): return ''
460
464
461 # meat of the code begins
465 # meat of the code begins
462 if type(etype) is types.ClassType:
466 try:
463 etype = etype.__name__
467 etype = etype.__name__
468 except AttributeError:
469 pass
464
470
465 if self.long_header:
471 if self.long_header:
466 # Header with the exception type, python version, and date
472 # Header with the exception type, python version, and date
467 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
473 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
468 date = time.ctime(time.time())
474 date = time.ctime(time.time())
469
475
470 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
476 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
471 exc, ' '*(75-len(str(etype))-len(pyver)),
477 exc, ' '*(75-len(str(etype))-len(pyver)),
472 pyver, string.rjust(date, 75) )
478 pyver, string.rjust(date, 75) )
473 head += "\nA problem occured executing Python code. Here is the sequence of function"\
479 head += "\nA problem occured executing Python code. Here is the sequence of function"\
474 "\ncalls leading up to the error, with the most recent (innermost) call last."
480 "\ncalls leading up to the error, with the most recent (innermost) call last."
475 else:
481 else:
476 # Simplified header
482 # Simplified header
477 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
483 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
478 string.rjust('Traceback (most recent call last)',
484 string.rjust('Traceback (most recent call last)',
479 75 - len(str(etype)) ) )
485 75 - len(str(etype)) ) )
480 frames = []
486 frames = []
481 # Flush cache before calling inspect. This helps alleviate some of the
487 # Flush cache before calling inspect. This helps alleviate some of the
482 # problems with python 2.3's inspect.py.
488 # problems with python 2.3's inspect.py.
483 linecache.checkcache()
489 linecache.checkcache()
484 # Drop topmost frames if requested
490 # Drop topmost frames if requested
485 try:
491 try:
486 # Try the default getinnerframes and Alex's: Alex's fixes some
492 # Try the default getinnerframes and Alex's: Alex's fixes some
487 # problems, but it generates empty tracebacks for console errors
493 # problems, but it generates empty tracebacks for console errors
488 # (5 blanks lines) where none should be returned.
494 # (5 blanks lines) where none should be returned.
489 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
495 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
490 #print 'python records:', records # dbg
496 #print 'python records:', records # dbg
491 records = _fixed_getinnerframes(etb, context,self.tb_offset)
497 records = _fixed_getinnerframes(etb, context,self.tb_offset)
492 #print 'alex records:', records # dbg
498 #print 'alex records:', records # dbg
493 except:
499 except:
494
500
495 # FIXME: I've been getting many crash reports from python 2.3
501 # FIXME: I've been getting many crash reports from python 2.3
496 # users, traceable to inspect.py. If I can find a small test-case
502 # users, traceable to inspect.py. If I can find a small test-case
497 # to reproduce this, I should either write a better workaround or
503 # to reproduce this, I should either write a better workaround or
498 # file a bug report against inspect (if that's the real problem).
504 # file a bug report against inspect (if that's the real problem).
499 # So far, I haven't been able to find an isolated example to
505 # So far, I haven't been able to find an isolated example to
500 # reproduce the problem.
506 # reproduce the problem.
501 inspect_error()
507 inspect_error()
502 traceback.print_exc(file=Term.cerr)
508 traceback.print_exc(file=Term.cerr)
503 info('\nUnfortunately, your original traceback can not be constructed.\n')
509 info('\nUnfortunately, your original traceback can not be constructed.\n')
504 return ''
510 return ''
505
511
506 # build some color string templates outside these nested loops
512 # build some color string templates outside these nested loops
507 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
513 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
508 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
514 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
509 ColorsNormal)
515 ColorsNormal)
510 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
516 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
511 (Colors.vName, Colors.valEm, ColorsNormal)
517 (Colors.vName, Colors.valEm, ColorsNormal)
512 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
518 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
513 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
519 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
514 Colors.vName, ColorsNormal)
520 Colors.vName, ColorsNormal)
515 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
521 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
516 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
522 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
517 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
523 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
518 ColorsNormal)
524 ColorsNormal)
519
525
520 # now, loop over all records printing context and info
526 # now, loop over all records printing context and info
521 abspath = os.path.abspath
527 abspath = os.path.abspath
522 for frame, file, lnum, func, lines, index in records:
528 for frame, file, lnum, func, lines, index in records:
523 #print '*** record:',file,lnum,func,lines,index # dbg
529 #print '*** record:',file,lnum,func,lines,index # dbg
524 try:
530 try:
525 file = file and abspath(file) or '?'
531 file = file and abspath(file) or '?'
526 except OSError:
532 except OSError:
527 # if file is '<console>' or something not in the filesystem,
533 # if file is '<console>' or something not in the filesystem,
528 # the abspath call will throw an OSError. Just ignore it and
534 # the abspath call will throw an OSError. Just ignore it and
529 # keep the original file string.
535 # keep the original file string.
530 pass
536 pass
531 link = tpl_link % file
537 link = tpl_link % file
532 try:
538 try:
533 args, varargs, varkw, locals = inspect.getargvalues(frame)
539 args, varargs, varkw, locals = inspect.getargvalues(frame)
534 except:
540 except:
535 # This can happen due to a bug in python2.3. We should be
541 # This can happen due to a bug in python2.3. We should be
536 # able to remove this try/except when 2.4 becomes a
542 # able to remove this try/except when 2.4 becomes a
537 # requirement. Bug details at http://python.org/sf/1005466
543 # requirement. Bug details at http://python.org/sf/1005466
538 inspect_error()
544 inspect_error()
539 traceback.print_exc(file=Term.cerr)
545 traceback.print_exc(file=Term.cerr)
540 info("\nIPython's exception reporting continues...\n")
546 info("\nIPython's exception reporting continues...\n")
541
547
542 if func == '?':
548 if func == '?':
543 call = ''
549 call = ''
544 else:
550 else:
545 # Decide whether to include variable details or not
551 # Decide whether to include variable details or not
546 var_repr = self.include_vars and eqrepr or nullrepr
552 var_repr = self.include_vars and eqrepr or nullrepr
547 try:
553 try:
548 call = tpl_call % (func,inspect.formatargvalues(args,
554 call = tpl_call % (func,inspect.formatargvalues(args,
549 varargs, varkw,
555 varargs, varkw,
550 locals,formatvalue=var_repr))
556 locals,formatvalue=var_repr))
551 except KeyError:
557 except KeyError:
552 # Very odd crash from inspect.formatargvalues(). The
558 # Very odd crash from inspect.formatargvalues(). The
553 # scenario under which it appeared was a call to
559 # scenario under which it appeared was a call to
554 # view(array,scale) in NumTut.view.view(), where scale had
560 # view(array,scale) in NumTut.view.view(), where scale had
555 # been defined as a scalar (it should be a tuple). Somehow
561 # been defined as a scalar (it should be a tuple). Somehow
556 # inspect messes up resolving the argument list of view()
562 # inspect messes up resolving the argument list of view()
557 # and barfs out. At some point I should dig into this one
563 # and barfs out. At some point I should dig into this one
558 # and file a bug report about it.
564 # and file a bug report about it.
559 inspect_error()
565 inspect_error()
560 traceback.print_exc(file=Term.cerr)
566 traceback.print_exc(file=Term.cerr)
561 info("\nIPython's exception reporting continues...\n")
567 info("\nIPython's exception reporting continues...\n")
562 call = tpl_call_fail % func
568 call = tpl_call_fail % func
563
569
564 # Initialize a list of names on the current line, which the
570 # Initialize a list of names on the current line, which the
565 # tokenizer below will populate.
571 # tokenizer below will populate.
566 names = []
572 names = []
567
573
568 def tokeneater(token_type, token, start, end, line):
574 def tokeneater(token_type, token, start, end, line):
569 """Stateful tokeneater which builds dotted names.
575 """Stateful tokeneater which builds dotted names.
570
576
571 The list of names it appends to (from the enclosing scope) can
577 The list of names it appends to (from the enclosing scope) can
572 contain repeated composite names. This is unavoidable, since
578 contain repeated composite names. This is unavoidable, since
573 there is no way to disambguate partial dotted structures until
579 there is no way to disambguate partial dotted structures until
574 the full list is known. The caller is responsible for pruning
580 the full list is known. The caller is responsible for pruning
575 the final list of duplicates before using it."""
581 the final list of duplicates before using it."""
576
582
577 # build composite names
583 # build composite names
578 if token == '.':
584 if token == '.':
579 try:
585 try:
580 names[-1] += '.'
586 names[-1] += '.'
581 # store state so the next token is added for x.y.z names
587 # store state so the next token is added for x.y.z names
582 tokeneater.name_cont = True
588 tokeneater.name_cont = True
583 return
589 return
584 except IndexError:
590 except IndexError:
585 pass
591 pass
586 if token_type == tokenize.NAME and token not in keyword.kwlist:
592 if token_type == tokenize.NAME and token not in keyword.kwlist:
587 if tokeneater.name_cont:
593 if tokeneater.name_cont:
588 # Dotted names
594 # Dotted names
589 names[-1] += token
595 names[-1] += token
590 tokeneater.name_cont = False
596 tokeneater.name_cont = False
591 else:
597 else:
592 # Regular new names. We append everything, the caller
598 # Regular new names. We append everything, the caller
593 # will be responsible for pruning the list later. It's
599 # will be responsible for pruning the list later. It's
594 # very tricky to try to prune as we go, b/c composite
600 # very tricky to try to prune as we go, b/c composite
595 # names can fool us. The pruning at the end is easy
601 # names can fool us. The pruning at the end is easy
596 # to do (or the caller can print a list with repeated
602 # to do (or the caller can print a list with repeated
597 # names if so desired.
603 # names if so desired.
598 names.append(token)
604 names.append(token)
599 elif token_type == tokenize.NEWLINE:
605 elif token_type == tokenize.NEWLINE:
600 raise IndexError
606 raise IndexError
601 # we need to store a bit of state in the tokenizer to build
607 # we need to store a bit of state in the tokenizer to build
602 # dotted names
608 # dotted names
603 tokeneater.name_cont = False
609 tokeneater.name_cont = False
604
610
605 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
611 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
606 line = getline(file, lnum[0])
612 line = getline(file, lnum[0])
607 lnum[0] += 1
613 lnum[0] += 1
608 return line
614 return line
609
615
610 # Build the list of names on this line of code where the exception
616 # Build the list of names on this line of code where the exception
611 # occurred.
617 # occurred.
612 try:
618 try:
613 # This builds the names list in-place by capturing it from the
619 # This builds the names list in-place by capturing it from the
614 # enclosing scope.
620 # enclosing scope.
615 tokenize.tokenize(linereader, tokeneater)
621 tokenize.tokenize(linereader, tokeneater)
616 except IndexError:
622 except IndexError:
617 # signals exit of tokenizer
623 # signals exit of tokenizer
618 pass
624 pass
619 except tokenize.TokenError,msg:
625 except tokenize.TokenError,msg:
620 _m = ("An unexpected error occurred while tokenizing input\n"
626 _m = ("An unexpected error occurred while tokenizing input\n"
621 "The following traceback may be corrupted or invalid\n"
627 "The following traceback may be corrupted or invalid\n"
622 "The error message is: %s\n" % msg)
628 "The error message is: %s\n" % msg)
623 error(_m)
629 error(_m)
624
630
625 # prune names list of duplicates, but keep the right order
631 # prune names list of duplicates, but keep the right order
626 unique_names = uniq_stable(names)
632 unique_names = uniq_stable(names)
627
633
628 # Start loop over vars
634 # Start loop over vars
629 lvals = []
635 lvals = []
630 if self.include_vars:
636 if self.include_vars:
631 for name_full in unique_names:
637 for name_full in unique_names:
632 name_base = name_full.split('.',1)[0]
638 name_base = name_full.split('.',1)[0]
633 if name_base in frame.f_code.co_varnames:
639 if name_base in frame.f_code.co_varnames:
634 if locals.has_key(name_base):
640 if locals.has_key(name_base):
635 try:
641 try:
636 value = repr(eval(name_full,locals))
642 value = repr(eval(name_full,locals))
637 except:
643 except:
638 value = undefined
644 value = undefined
639 else:
645 else:
640 value = undefined
646 value = undefined
641 name = tpl_local_var % name_full
647 name = tpl_local_var % name_full
642 else:
648 else:
643 if frame.f_globals.has_key(name_base):
649 if frame.f_globals.has_key(name_base):
644 try:
650 try:
645 value = repr(eval(name_full,frame.f_globals))
651 value = repr(eval(name_full,frame.f_globals))
646 except:
652 except:
647 value = undefined
653 value = undefined
648 else:
654 else:
649 value = undefined
655 value = undefined
650 name = tpl_global_var % name_full
656 name = tpl_global_var % name_full
651 lvals.append(tpl_name_val % (name,value))
657 lvals.append(tpl_name_val % (name,value))
652 if lvals:
658 if lvals:
653 lvals = '%s%s' % (indent,em_normal.join(lvals))
659 lvals = '%s%s' % (indent,em_normal.join(lvals))
654 else:
660 else:
655 lvals = ''
661 lvals = ''
656
662
657 level = '%s %s\n' % (link,call)
663 level = '%s %s\n' % (link,call)
658
664
659 if index is None:
665 if index is None:
660 frames.append(level)
666 frames.append(level)
661 else:
667 else:
662 frames.append('%s%s' % (level,''.join(
668 frames.append('%s%s' % (level,''.join(
663 _formatTracebackLines(lnum,index,lines,Colors,lvals,
669 _formatTracebackLines(lnum,index,lines,Colors,lvals,
664 col_scheme))))
670 col_scheme))))
665
671
666 # Get (safely) a string form of the exception info
672 # Get (safely) a string form of the exception info
667 try:
673 try:
668 etype_str,evalue_str = map(str,(etype,evalue))
674 etype_str,evalue_str = map(str,(etype,evalue))
669 except:
675 except:
670 # User exception is improperly defined.
676 # User exception is improperly defined.
671 etype,evalue = str,sys.exc_info()[:2]
677 etype,evalue = str,sys.exc_info()[:2]
672 etype_str,evalue_str = map(str,(etype,evalue))
678 etype_str,evalue_str = map(str,(etype,evalue))
673 # ... and format it
679 # ... and format it
674 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
680 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
675 ColorsNormal, evalue_str)]
681 ColorsNormal, evalue_str)]
676 if type(evalue) is types.InstanceType:
682 if type(evalue) is types.InstanceType:
677 try:
683 try:
678 names = [w for w in dir(evalue) if isinstance(w, basestring)]
684 names = [w for w in dir(evalue) if isinstance(w, basestring)]
679 except:
685 except:
680 # Every now and then, an object with funny inernals blows up
686 # Every now and then, an object with funny inernals blows up
681 # when dir() is called on it. We do the best we can to report
687 # when dir() is called on it. We do the best we can to report
682 # the problem and continue
688 # the problem and continue
683 _m = '%sException reporting error (object with broken dir())%s:'
689 _m = '%sException reporting error (object with broken dir())%s:'
684 exception.append(_m % (Colors.excName,ColorsNormal))
690 exception.append(_m % (Colors.excName,ColorsNormal))
685 etype_str,evalue_str = map(str,sys.exc_info()[:2])
691 etype_str,evalue_str = map(str,sys.exc_info()[:2])
686 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
692 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
687 ColorsNormal, evalue_str))
693 ColorsNormal, evalue_str))
688 names = []
694 names = []
689 for name in names:
695 for name in names:
690 value = text_repr(getattr(evalue, name))
696 value = text_repr(getattr(evalue, name))
691 exception.append('\n%s%s = %s' % (indent, name, value))
697 exception.append('\n%s%s = %s' % (indent, name, value))
692 # return all our info assembled as a single string
698 # return all our info assembled as a single string
693 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
699 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
694
700
695 def debugger(self,force=False):
701 def debugger(self,force=False):
696 """Call up the pdb debugger if desired, always clean up the tb
702 """Call up the pdb debugger if desired, always clean up the tb
697 reference.
703 reference.
698
704
699 Keywords:
705 Keywords:
700
706
701 - force(False): by default, this routine checks the instance call_pdb
707 - force(False): by default, this routine checks the instance call_pdb
702 flag and does not actually invoke the debugger if the flag is false.
708 flag and does not actually invoke the debugger if the flag is false.
703 The 'force' option forces the debugger to activate even if the flag
709 The 'force' option forces the debugger to activate even if the flag
704 is false.
710 is false.
705
711
706 If the call_pdb flag is set, the pdb interactive debugger is
712 If the call_pdb flag is set, the pdb interactive debugger is
707 invoked. In all cases, the self.tb reference to the current traceback
713 invoked. In all cases, the self.tb reference to the current traceback
708 is deleted to prevent lingering references which hamper memory
714 is deleted to prevent lingering references which hamper memory
709 management.
715 management.
710
716
711 Note that each call to pdb() does an 'import readline', so if your app
717 Note that each call to pdb() does an 'import readline', so if your app
712 requires a special setup for the readline completers, you'll have to
718 requires a special setup for the readline completers, you'll have to
713 fix that by hand after invoking the exception handler."""
719 fix that by hand after invoking the exception handler."""
714
720
715 if force or self.call_pdb:
721 if force or self.call_pdb:
716 if self.pdb is None:
722 if self.pdb is None:
717 self.pdb = Debugger.Pdb(
723 self.pdb = Debugger.Pdb(
718 self.color_scheme_table.active_scheme_name)
724 self.color_scheme_table.active_scheme_name)
719 # the system displayhook may have changed, restore the original
725 # the system displayhook may have changed, restore the original
720 # for pdb
726 # for pdb
721 dhook = sys.displayhook
727 dhook = sys.displayhook
722 sys.displayhook = sys.__displayhook__
728 sys.displayhook = sys.__displayhook__
723 self.pdb.reset()
729 self.pdb.reset()
724 # Find the right frame so we don't pop up inside ipython itself
730 # Find the right frame so we don't pop up inside ipython itself
725 if hasattr(self,'tb'):
731 if hasattr(self,'tb'):
726 etb = self.tb
732 etb = self.tb
727 else:
733 else:
728 etb = self.tb = sys.last_traceback
734 etb = self.tb = sys.last_traceback
729 while self.tb.tb_next is not None:
735 while self.tb.tb_next is not None:
730 self.tb = self.tb.tb_next
736 self.tb = self.tb.tb_next
731 try:
737 try:
732 if etb and etb.tb_next:
738 if etb and etb.tb_next:
733 etb = etb.tb_next
739 etb = etb.tb_next
734 self.pdb.botframe = etb.tb_frame
740 self.pdb.botframe = etb.tb_frame
735 self.pdb.interaction(self.tb.tb_frame, self.tb)
741 self.pdb.interaction(self.tb.tb_frame, self.tb)
736 finally:
742 finally:
737 sys.displayhook = dhook
743 sys.displayhook = dhook
738
744
739 if hasattr(self,'tb'):
745 if hasattr(self,'tb'):
740 del self.tb
746 del self.tb
741
747
742 def handler(self, info=None):
748 def handler(self, info=None):
743 (etype, evalue, etb) = info or sys.exc_info()
749 (etype, evalue, etb) = info or sys.exc_info()
744 self.tb = etb
750 self.tb = etb
745 Term.cout.flush()
751 Term.cout.flush()
746 Term.cerr.flush()
752 Term.cerr.flush()
747 print >> Term.cerr, self.text(etype, evalue, etb)
753 print >> Term.cerr, self.text(etype, evalue, etb)
748
754
749 # Changed so an instance can just be called as VerboseTB_inst() and print
755 # Changed so an instance can just be called as VerboseTB_inst() and print
750 # out the right info on its own.
756 # out the right info on its own.
751 def __call__(self, etype=None, evalue=None, etb=None):
757 def __call__(self, etype=None, evalue=None, etb=None):
752 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
758 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
753 if etb is None:
759 if etb is None:
754 self.handler()
760 self.handler()
755 else:
761 else:
756 self.handler((etype, evalue, etb))
762 self.handler((etype, evalue, etb))
757 self.debugger()
763 self.debugger()
758
764
759 #----------------------------------------------------------------------------
765 #----------------------------------------------------------------------------
760 class FormattedTB(VerboseTB,ListTB):
766 class FormattedTB(VerboseTB,ListTB):
761 """Subclass ListTB but allow calling with a traceback.
767 """Subclass ListTB but allow calling with a traceback.
762
768
763 It can thus be used as a sys.excepthook for Python > 2.1.
769 It can thus be used as a sys.excepthook for Python > 2.1.
764
770
765 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
771 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
766
772
767 Allows a tb_offset to be specified. This is useful for situations where
773 Allows a tb_offset to be specified. This is useful for situations where
768 one needs to remove a number of topmost frames from the traceback (such as
774 one needs to remove a number of topmost frames from the traceback (such as
769 occurs with python programs that themselves execute other python code,
775 occurs with python programs that themselves execute other python code,
770 like Python shells). """
776 like Python shells). """
771
777
772 def __init__(self, mode = 'Plain', color_scheme='Linux',
778 def __init__(self, mode = 'Plain', color_scheme='Linux',
773 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
779 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
774
780
775 # NEVER change the order of this list. Put new modes at the end:
781 # NEVER change the order of this list. Put new modes at the end:
776 self.valid_modes = ['Plain','Context','Verbose']
782 self.valid_modes = ['Plain','Context','Verbose']
777 self.verbose_modes = self.valid_modes[1:3]
783 self.verbose_modes = self.valid_modes[1:3]
778
784
779 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
785 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
780 call_pdb=call_pdb,include_vars=include_vars)
786 call_pdb=call_pdb,include_vars=include_vars)
781 self.set_mode(mode)
787 self.set_mode(mode)
782
788
783 def _extract_tb(self,tb):
789 def _extract_tb(self,tb):
784 if tb:
790 if tb:
785 return traceback.extract_tb(tb)
791 return traceback.extract_tb(tb)
786 else:
792 else:
787 return None
793 return None
788
794
789 def text(self, etype, value, tb,context=5,mode=None):
795 def text(self, etype, value, tb,context=5,mode=None):
790 """Return formatted traceback.
796 """Return formatted traceback.
791
797
792 If the optional mode parameter is given, it overrides the current
798 If the optional mode parameter is given, it overrides the current
793 mode."""
799 mode."""
794
800
795 if mode is None:
801 if mode is None:
796 mode = self.mode
802 mode = self.mode
797 if mode in self.verbose_modes:
803 if mode in self.verbose_modes:
798 # verbose modes need a full traceback
804 # verbose modes need a full traceback
799 return VerboseTB.text(self,etype, value, tb,context=5)
805 return VerboseTB.text(self,etype, value, tb,context=5)
800 else:
806 else:
801 # We must check the source cache because otherwise we can print
807 # We must check the source cache because otherwise we can print
802 # out-of-date source code.
808 # out-of-date source code.
803 linecache.checkcache()
809 linecache.checkcache()
804 # Now we can extract and format the exception
810 # Now we can extract and format the exception
805 elist = self._extract_tb(tb)
811 elist = self._extract_tb(tb)
806 if len(elist) > self.tb_offset:
812 if len(elist) > self.tb_offset:
807 del elist[:self.tb_offset]
813 del elist[:self.tb_offset]
808 return ListTB.text(self,etype,value,elist)
814 return ListTB.text(self,etype,value,elist)
809
815
810 def set_mode(self,mode=None):
816 def set_mode(self,mode=None):
811 """Switch to the desired mode.
817 """Switch to the desired mode.
812
818
813 If mode is not specified, cycles through the available modes."""
819 If mode is not specified, cycles through the available modes."""
814
820
815 if not mode:
821 if not mode:
816 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
822 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
817 len(self.valid_modes)
823 len(self.valid_modes)
818 self.mode = self.valid_modes[new_idx]
824 self.mode = self.valid_modes[new_idx]
819 elif mode not in self.valid_modes:
825 elif mode not in self.valid_modes:
820 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
826 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
821 'Valid modes: '+str(self.valid_modes)
827 'Valid modes: '+str(self.valid_modes)
822 else:
828 else:
823 self.mode = mode
829 self.mode = mode
824 # include variable details only in 'Verbose' mode
830 # include variable details only in 'Verbose' mode
825 self.include_vars = (self.mode == self.valid_modes[2])
831 self.include_vars = (self.mode == self.valid_modes[2])
826
832
827 # some convenient shorcuts
833 # some convenient shorcuts
828 def plain(self):
834 def plain(self):
829 self.set_mode(self.valid_modes[0])
835 self.set_mode(self.valid_modes[0])
830
836
831 def context(self):
837 def context(self):
832 self.set_mode(self.valid_modes[1])
838 self.set_mode(self.valid_modes[1])
833
839
834 def verbose(self):
840 def verbose(self):
835 self.set_mode(self.valid_modes[2])
841 self.set_mode(self.valid_modes[2])
836
842
837 #----------------------------------------------------------------------------
843 #----------------------------------------------------------------------------
838 class AutoFormattedTB(FormattedTB):
844 class AutoFormattedTB(FormattedTB):
839 """A traceback printer which can be called on the fly.
845 """A traceback printer which can be called on the fly.
840
846
841 It will find out about exceptions by itself.
847 It will find out about exceptions by itself.
842
848
843 A brief example:
849 A brief example:
844
850
845 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
851 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
846 try:
852 try:
847 ...
853 ...
848 except:
854 except:
849 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
855 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
850 """
856 """
851 def __call__(self,etype=None,evalue=None,etb=None,
857 def __call__(self,etype=None,evalue=None,etb=None,
852 out=None,tb_offset=None):
858 out=None,tb_offset=None):
853 """Print out a formatted exception traceback.
859 """Print out a formatted exception traceback.
854
860
855 Optional arguments:
861 Optional arguments:
856 - out: an open file-like object to direct output to.
862 - out: an open file-like object to direct output to.
857
863
858 - tb_offset: the number of frames to skip over in the stack, on a
864 - tb_offset: the number of frames to skip over in the stack, on a
859 per-call basis (this overrides temporarily the instance's tb_offset
865 per-call basis (this overrides temporarily the instance's tb_offset
860 given at initialization time. """
866 given at initialization time. """
861
867
862 if out is None:
868 if out is None:
863 out = Term.cerr
869 out = Term.cerr
864 Term.cout.flush()
870 Term.cout.flush()
865 out.flush()
871 out.flush()
866 if tb_offset is not None:
872 if tb_offset is not None:
867 tb_offset, self.tb_offset = self.tb_offset, tb_offset
873 tb_offset, self.tb_offset = self.tb_offset, tb_offset
868 print >> out, self.text(etype, evalue, etb)
874 print >> out, self.text(etype, evalue, etb)
869 self.tb_offset = tb_offset
875 self.tb_offset = tb_offset
870 else:
876 else:
871 print >> out, self.text(etype, evalue, etb)
877 print >> out, self.text(etype, evalue, etb)
872 self.debugger()
878 self.debugger()
873
879
874 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
880 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
875 if etype is None:
881 if etype is None:
876 etype,value,tb = sys.exc_info()
882 etype,value,tb = sys.exc_info()
877 self.tb = tb
883 self.tb = tb
878 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
884 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
879
885
880 #---------------------------------------------------------------------------
886 #---------------------------------------------------------------------------
881 # A simple class to preserve Nathan's original functionality.
887 # A simple class to preserve Nathan's original functionality.
882 class ColorTB(FormattedTB):
888 class ColorTB(FormattedTB):
883 """Shorthand to initialize a FormattedTB in Linux colors mode."""
889 """Shorthand to initialize a FormattedTB in Linux colors mode."""
884 def __init__(self,color_scheme='Linux',call_pdb=0):
890 def __init__(self,color_scheme='Linux',call_pdb=0):
885 FormattedTB.__init__(self,color_scheme=color_scheme,
891 FormattedTB.__init__(self,color_scheme=color_scheme,
886 call_pdb=call_pdb)
892 call_pdb=call_pdb)
887
893
888 #----------------------------------------------------------------------------
894 #----------------------------------------------------------------------------
889 # module testing (minimal)
895 # module testing (minimal)
890 if __name__ == "__main__":
896 if __name__ == "__main__":
891 def spam(c, (d, e)):
897 def spam(c, (d, e)):
892 x = c + d
898 x = c + d
893 y = c * d
899 y = c * d
894 foo(x, y)
900 foo(x, y)
895
901
896 def foo(a, b, bar=1):
902 def foo(a, b, bar=1):
897 eggs(a, b + bar)
903 eggs(a, b + bar)
898
904
899 def eggs(f, g, z=globals()):
905 def eggs(f, g, z=globals()):
900 h = f + g
906 h = f + g
901 i = f - g
907 i = f - g
902 return h / i
908 return h / i
903
909
904 print ''
910 print ''
905 print '*** Before ***'
911 print '*** Before ***'
906 try:
912 try:
907 print spam(1, (2, 3))
913 print spam(1, (2, 3))
908 except:
914 except:
909 traceback.print_exc()
915 traceback.print_exc()
910 print ''
916 print ''
911
917
912 handler = ColorTB()
918 handler = ColorTB()
913 print '*** ColorTB ***'
919 print '*** ColorTB ***'
914 try:
920 try:
915 print spam(1, (2, 3))
921 print spam(1, (2, 3))
916 except:
922 except:
917 apply(handler, sys.exc_info() )
923 apply(handler, sys.exc_info() )
918 print ''
924 print ''
919
925
920 handler = VerboseTB()
926 handler = VerboseTB()
921 print '*** VerboseTB ***'
927 print '*** VerboseTB ***'
922 try:
928 try:
923 print spam(1, (2, 3))
929 print spam(1, (2, 3))
924 except:
930 except:
925 apply(handler, sys.exc_info() )
931 apply(handler, sys.exc_info() )
926 print ''
932 print ''
927
933
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now