##// END OF EJS Templates
Don't assume that SyntaxTB is always called with a SyntaxError...
Thomas Kluyver -
Show More
@@ -1,1265 +1,1266 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
12
13 import sys,ultratb
13 import sys,ultratb
14 sys.excepthook = ultratb.ColorTB()
14 sys.excepthook = ultratb.ColorTB()
15
15
16 * VerboseTB
16 * VerboseTB
17 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
18 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 of useful info when a traceback occurs. Ping originally had it spit out HTML
19 and intended it for CGI programmers, but why should they have all the fun? I
19 and intended it for CGI programmers, but why should they have all the fun? I
20 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 altered it to spit out colored text to the terminal. It's a bit overwhelming,
21 but kind of neat, and maybe useful for long-running programs that you believe
21 but kind of neat, and maybe useful for long-running programs that you believe
22 are bug-free. If a crash *does* occur in that type of program you want details.
22 are bug-free. If a crash *does* occur in that type of program you want details.
23 Give it a shot--you'll love it or you'll hate it.
23 Give it a shot--you'll love it or you'll hate it.
24
24
25 .. note::
25 .. note::
26
26
27 The Verbose mode prints the variables currently visible where the exception
27 The Verbose mode prints the variables currently visible where the exception
28 happened (shortening their strings if too long). This can potentially be
28 happened (shortening their strings if too long). This can potentially be
29 very slow, if you happen to have a huge data structure whose string
29 very slow, if you happen to have a huge data structure whose string
30 representation is complex to compute. Your computer may appear to freeze for
30 representation is complex to compute. Your computer may appear to freeze for
31 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
32 with Ctrl-C (maybe hitting it more than once).
32 with Ctrl-C (maybe hitting it more than once).
33
33
34 If you encounter this kind of situation often, you may want to use the
34 If you encounter this kind of situation often, you may want to use the
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
36 variables (but otherwise includes the information and context given by
36 variables (but otherwise includes the information and context given by
37 Verbose).
37 Verbose).
38
38
39
39
40 Installation instructions for ColorTB::
40 Installation instructions for ColorTB::
41
41
42 import sys,ultratb
42 import sys,ultratb
43 sys.excepthook = ultratb.VerboseTB()
43 sys.excepthook = ultratb.VerboseTB()
44
44
45 Note: Much of the code in this module was lifted verbatim from the standard
45 Note: Much of the code in this module was lifted verbatim from the standard
46 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
46 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
47
47
48 Color schemes
48 Color schemes
49 -------------
49 -------------
50
50
51 The colors are defined in the class TBTools through the use of the
51 The colors are defined in the class TBTools through the use of the
52 ColorSchemeTable class. Currently the following exist:
52 ColorSchemeTable class. Currently the following exist:
53
53
54 - NoColor: allows all of this module to be used in any terminal (the color
54 - NoColor: allows all of this module to be used in any terminal (the color
55 escapes are just dummy blank strings).
55 escapes are just dummy blank strings).
56
56
57 - Linux: is meant to look good in a terminal like the Linux console (black
57 - Linux: is meant to look good in a terminal like the Linux console (black
58 or very dark background).
58 or very dark background).
59
59
60 - LightBG: similar to Linux but swaps dark/light colors to be more readable
60 - LightBG: similar to Linux but swaps dark/light colors to be more readable
61 in light background terminals.
61 in light background terminals.
62
62
63 You can implement other color schemes easily, the syntax is fairly
63 You can implement other color schemes easily, the syntax is fairly
64 self-explanatory. Please send back new schemes you develop to the author for
64 self-explanatory. Please send back new schemes you develop to the author for
65 possible inclusion in future releases.
65 possible inclusion in future releases.
66
66
67 Inheritance diagram:
67 Inheritance diagram:
68
68
69 .. inheritance-diagram:: IPython.core.ultratb
69 .. inheritance-diagram:: IPython.core.ultratb
70 :parts: 3
70 :parts: 3
71 """
71 """
72
72
73 #*****************************************************************************
73 #*****************************************************************************
74 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
74 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
75 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
75 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
76 #
76 #
77 # Distributed under the terms of the BSD License. The full license is in
77 # Distributed under the terms of the BSD License. The full license is in
78 # the file COPYING, distributed as part of this software.
78 # the file COPYING, distributed as part of this software.
79 #*****************************************************************************
79 #*****************************************************************************
80
80
81 from __future__ import unicode_literals
81 from __future__ import unicode_literals
82
82
83 import inspect
83 import inspect
84 import keyword
84 import keyword
85 import linecache
85 import linecache
86 import os
86 import os
87 import pydoc
87 import pydoc
88 import re
88 import re
89 import sys
89 import sys
90 import time
90 import time
91 import tokenize
91 import tokenize
92 import traceback
92 import traceback
93 import types
93 import types
94
94
95 try: # Python 2
95 try: # Python 2
96 generate_tokens = tokenize.generate_tokens
96 generate_tokens = tokenize.generate_tokens
97 except AttributeError: # Python 3
97 except AttributeError: # Python 3
98 generate_tokens = tokenize.tokenize
98 generate_tokens = tokenize.tokenize
99
99
100 # For purposes of monkeypatching inspect to fix a bug in it.
100 # For purposes of monkeypatching inspect to fix a bug in it.
101 from inspect import getsourcefile, getfile, getmodule,\
101 from inspect import getsourcefile, getfile, getmodule,\
102 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
102 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
103
103
104 # IPython's own modules
104 # IPython's own modules
105 # Modified pdb which doesn't damage IPython's readline handling
105 # Modified pdb which doesn't damage IPython's readline handling
106 from IPython import get_ipython
106 from IPython import get_ipython
107 from IPython.core import debugger
107 from IPython.core import debugger
108 from IPython.core.display_trap import DisplayTrap
108 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.excolors import exception_colors
109 from IPython.core.excolors import exception_colors
110 from IPython.utils import PyColorize
110 from IPython.utils import PyColorize
111 from IPython.utils import io
111 from IPython.utils import io
112 from IPython.utils import openpy
112 from IPython.utils import openpy
113 from IPython.utils import path as util_path
113 from IPython.utils import path as util_path
114 from IPython.utils import py3compat
114 from IPython.utils import py3compat
115 from IPython.utils import ulinecache
115 from IPython.utils import ulinecache
116 from IPython.utils.data import uniq_stable
116 from IPython.utils.data import uniq_stable
117 from IPython.utils.warn import info, error
117 from IPython.utils.warn import info, error
118
118
119 # Globals
119 # Globals
120 # amount of space to put line numbers before verbose tracebacks
120 # amount of space to put line numbers before verbose tracebacks
121 INDENT_SIZE = 8
121 INDENT_SIZE = 8
122
122
123 # Default color scheme. This is used, for example, by the traceback
123 # Default color scheme. This is used, for example, by the traceback
124 # formatter. When running in an actual IPython instance, the user's rc.colors
124 # formatter. When running in an actual IPython instance, the user's rc.colors
125 # value is used, but havinga module global makes this functionality available
125 # value is used, but havinga module global makes this functionality available
126 # to users of ultratb who are NOT running inside ipython.
126 # to users of ultratb who are NOT running inside ipython.
127 DEFAULT_SCHEME = 'NoColor'
127 DEFAULT_SCHEME = 'NoColor'
128
128
129 #---------------------------------------------------------------------------
129 #---------------------------------------------------------------------------
130 # Code begins
130 # Code begins
131
131
132 # Utility functions
132 # Utility functions
133 def inspect_error():
133 def inspect_error():
134 """Print a message about internal inspect errors.
134 """Print a message about internal inspect errors.
135
135
136 These are unfortunately quite common."""
136 These are unfortunately quite common."""
137
137
138 error('Internal Python error in the inspect module.\n'
138 error('Internal Python error in the inspect module.\n'
139 'Below is the traceback from this internal error.\n')
139 'Below is the traceback from this internal error.\n')
140
140
141 # This function is a monkeypatch we apply to the Python inspect module. We have
141 # This function is a monkeypatch we apply to the Python inspect module. We have
142 # now found when it's needed (see discussion on issue gh-1456), and we have a
142 # now found when it's needed (see discussion on issue gh-1456), and we have a
143 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
143 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
144 # the monkeypatch is not applied. TK, Aug 2012.
144 # the monkeypatch is not applied. TK, Aug 2012.
145 def findsource(object):
145 def findsource(object):
146 """Return the entire source file and starting line number for an object.
146 """Return the entire source file and starting line number for an object.
147
147
148 The argument may be a module, class, method, function, traceback, frame,
148 The argument may be a module, class, method, function, traceback, frame,
149 or code object. The source code is returned as a list of all the lines
149 or code object. The source code is returned as a list of all the lines
150 in the file and the line number indexes a line in that list. An IOError
150 in the file and the line number indexes a line in that list. An IOError
151 is raised if the source code cannot be retrieved.
151 is raised if the source code cannot be retrieved.
152
152
153 FIXED version with which we monkeypatch the stdlib to work around a bug."""
153 FIXED version with which we monkeypatch the stdlib to work around a bug."""
154
154
155 file = getsourcefile(object) or getfile(object)
155 file = getsourcefile(object) or getfile(object)
156 # If the object is a frame, then trying to get the globals dict from its
156 # If the object is a frame, then trying to get the globals dict from its
157 # module won't work. Instead, the frame object itself has the globals
157 # module won't work. Instead, the frame object itself has the globals
158 # dictionary.
158 # dictionary.
159 globals_dict = None
159 globals_dict = None
160 if inspect.isframe(object):
160 if inspect.isframe(object):
161 # XXX: can this ever be false?
161 # XXX: can this ever be false?
162 globals_dict = object.f_globals
162 globals_dict = object.f_globals
163 else:
163 else:
164 module = getmodule(object, file)
164 module = getmodule(object, file)
165 if module:
165 if module:
166 globals_dict = module.__dict__
166 globals_dict = module.__dict__
167 lines = linecache.getlines(file, globals_dict)
167 lines = linecache.getlines(file, globals_dict)
168 if not lines:
168 if not lines:
169 raise IOError('could not get source code')
169 raise IOError('could not get source code')
170
170
171 if ismodule(object):
171 if ismodule(object):
172 return lines, 0
172 return lines, 0
173
173
174 if isclass(object):
174 if isclass(object):
175 name = object.__name__
175 name = object.__name__
176 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
176 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
177 # make some effort to find the best matching class definition:
177 # make some effort to find the best matching class definition:
178 # use the one with the least indentation, which is the one
178 # use the one with the least indentation, which is the one
179 # that's most probably not inside a function definition.
179 # that's most probably not inside a function definition.
180 candidates = []
180 candidates = []
181 for i in range(len(lines)):
181 for i in range(len(lines)):
182 match = pat.match(lines[i])
182 match = pat.match(lines[i])
183 if match:
183 if match:
184 # if it's at toplevel, it's already the best one
184 # if it's at toplevel, it's already the best one
185 if lines[i][0] == 'c':
185 if lines[i][0] == 'c':
186 return lines, i
186 return lines, i
187 # else add whitespace to candidate list
187 # else add whitespace to candidate list
188 candidates.append((match.group(1), i))
188 candidates.append((match.group(1), i))
189 if candidates:
189 if candidates:
190 # this will sort by whitespace, and by line number,
190 # this will sort by whitespace, and by line number,
191 # less whitespace first
191 # less whitespace first
192 candidates.sort()
192 candidates.sort()
193 return lines, candidates[0][1]
193 return lines, candidates[0][1]
194 else:
194 else:
195 raise IOError('could not find class definition')
195 raise IOError('could not find class definition')
196
196
197 if ismethod(object):
197 if ismethod(object):
198 object = object.im_func
198 object = object.im_func
199 if isfunction(object):
199 if isfunction(object):
200 object = object.func_code
200 object = object.func_code
201 if istraceback(object):
201 if istraceback(object):
202 object = object.tb_frame
202 object = object.tb_frame
203 if isframe(object):
203 if isframe(object):
204 object = object.f_code
204 object = object.f_code
205 if iscode(object):
205 if iscode(object):
206 if not hasattr(object, 'co_firstlineno'):
206 if not hasattr(object, 'co_firstlineno'):
207 raise IOError('could not find function definition')
207 raise IOError('could not find function definition')
208 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
208 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
209 pmatch = pat.match
209 pmatch = pat.match
210 # fperez - fix: sometimes, co_firstlineno can give a number larger than
210 # fperez - fix: sometimes, co_firstlineno can give a number larger than
211 # the length of lines, which causes an error. Safeguard against that.
211 # the length of lines, which causes an error. Safeguard against that.
212 lnum = min(object.co_firstlineno,len(lines))-1
212 lnum = min(object.co_firstlineno,len(lines))-1
213 while lnum > 0:
213 while lnum > 0:
214 if pmatch(lines[lnum]): break
214 if pmatch(lines[lnum]): break
215 lnum -= 1
215 lnum -= 1
216
216
217 return lines, lnum
217 return lines, lnum
218 raise IOError('could not find code object')
218 raise IOError('could not find code object')
219
219
220 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
220 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
221 inspect.findsource = findsource
221 inspect.findsource = findsource
222
222
223 def fix_frame_records_filenames(records):
223 def fix_frame_records_filenames(records):
224 """Try to fix the filenames in each record from inspect.getinnerframes().
224 """Try to fix the filenames in each record from inspect.getinnerframes().
225
225
226 Particularly, modules loaded from within zip files have useless filenames
226 Particularly, modules loaded from within zip files have useless filenames
227 attached to their code object, and inspect.getinnerframes() just uses it.
227 attached to their code object, and inspect.getinnerframes() just uses it.
228 """
228 """
229 fixed_records = []
229 fixed_records = []
230 for frame, filename, line_no, func_name, lines, index in records:
230 for frame, filename, line_no, func_name, lines, index in records:
231 # Look inside the frame's globals dictionary for __file__, which should
231 # Look inside the frame's globals dictionary for __file__, which should
232 # be better.
232 # be better.
233 better_fn = frame.f_globals.get('__file__', None)
233 better_fn = frame.f_globals.get('__file__', None)
234 if isinstance(better_fn, str):
234 if isinstance(better_fn, str):
235 # Check the type just in case someone did something weird with
235 # Check the type just in case someone did something weird with
236 # __file__. It might also be None if the error occurred during
236 # __file__. It might also be None if the error occurred during
237 # import.
237 # import.
238 filename = better_fn
238 filename = better_fn
239 fixed_records.append((frame, filename, line_no, func_name, lines, index))
239 fixed_records.append((frame, filename, line_no, func_name, lines, index))
240 return fixed_records
240 return fixed_records
241
241
242
242
243 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
243 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
244 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
244 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
245
245
246 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
246 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
247
247
248 # If the error is at the console, don't build any context, since it would
248 # If the error is at the console, don't build any context, since it would
249 # otherwise produce 5 blank lines printed out (there is no file at the
249 # otherwise produce 5 blank lines printed out (there is no file at the
250 # console)
250 # console)
251 rec_check = records[tb_offset:]
251 rec_check = records[tb_offset:]
252 try:
252 try:
253 rname = rec_check[0][1]
253 rname = rec_check[0][1]
254 if rname == '<ipython console>' or rname.endswith('<string>'):
254 if rname == '<ipython console>' or rname.endswith('<string>'):
255 return rec_check
255 return rec_check
256 except IndexError:
256 except IndexError:
257 pass
257 pass
258
258
259 aux = traceback.extract_tb(etb)
259 aux = traceback.extract_tb(etb)
260 assert len(records) == len(aux)
260 assert len(records) == len(aux)
261 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
261 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
262 maybeStart = lnum-1 - context//2
262 maybeStart = lnum-1 - context//2
263 start = max(maybeStart, 0)
263 start = max(maybeStart, 0)
264 end = start + context
264 end = start + context
265 lines = ulinecache.getlines(file)[start:end]
265 lines = ulinecache.getlines(file)[start:end]
266 buf = list(records[i])
266 buf = list(records[i])
267 buf[LNUM_POS] = lnum
267 buf[LNUM_POS] = lnum
268 buf[INDEX_POS] = lnum - 1 - start
268 buf[INDEX_POS] = lnum - 1 - start
269 buf[LINES_POS] = lines
269 buf[LINES_POS] = lines
270 records[i] = tuple(buf)
270 records[i] = tuple(buf)
271 return records[tb_offset:]
271 return records[tb_offset:]
272
272
273 # Helper function -- largely belongs to VerboseTB, but we need the same
273 # Helper function -- largely belongs to VerboseTB, but we need the same
274 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
274 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
275 # can be recognized properly by ipython.el's py-traceback-line-re
275 # can be recognized properly by ipython.el's py-traceback-line-re
276 # (SyntaxErrors have to be treated specially because they have no traceback)
276 # (SyntaxErrors have to be treated specially because they have no traceback)
277
277
278 _parser = PyColorize.Parser()
278 _parser = PyColorize.Parser()
279
279
280 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
280 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
281 numbers_width = INDENT_SIZE - 1
281 numbers_width = INDENT_SIZE - 1
282 res = []
282 res = []
283 i = lnum - index
283 i = lnum - index
284
284
285 # This lets us get fully syntax-highlighted tracebacks.
285 # This lets us get fully syntax-highlighted tracebacks.
286 if scheme is None:
286 if scheme is None:
287 ipinst = get_ipython()
287 ipinst = get_ipython()
288 if ipinst is not None:
288 if ipinst is not None:
289 scheme = ipinst.colors
289 scheme = ipinst.colors
290 else:
290 else:
291 scheme = DEFAULT_SCHEME
291 scheme = DEFAULT_SCHEME
292
292
293 _line_format = _parser.format2
293 _line_format = _parser.format2
294
294
295 for line in lines:
295 for line in lines:
296 line = py3compat.cast_unicode(line)
296 line = py3compat.cast_unicode(line)
297
297
298 new_line, err = _line_format(line, 'str', scheme)
298 new_line, err = _line_format(line, 'str', scheme)
299 if not err: line = new_line
299 if not err: line = new_line
300
300
301 if i == lnum:
301 if i == lnum:
302 # This is the line with the error
302 # This is the line with the error
303 pad = numbers_width - len(str(i))
303 pad = numbers_width - len(str(i))
304 if pad >= 3:
304 if pad >= 3:
305 marker = '-'*(pad-3) + '-> '
305 marker = '-'*(pad-3) + '-> '
306 elif pad == 2:
306 elif pad == 2:
307 marker = '> '
307 marker = '> '
308 elif pad == 1:
308 elif pad == 1:
309 marker = '>'
309 marker = '>'
310 else:
310 else:
311 marker = ''
311 marker = ''
312 num = marker + str(i)
312 num = marker + str(i)
313 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
313 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
314 Colors.line, line, Colors.Normal)
314 Colors.line, line, Colors.Normal)
315 else:
315 else:
316 num = '%*s' % (numbers_width,i)
316 num = '%*s' % (numbers_width,i)
317 line = '%s%s%s %s' %(Colors.lineno, num,
317 line = '%s%s%s %s' %(Colors.lineno, num,
318 Colors.Normal, line)
318 Colors.Normal, line)
319
319
320 res.append(line)
320 res.append(line)
321 if lvals and i == lnum:
321 if lvals and i == lnum:
322 res.append(lvals + '\n')
322 res.append(lvals + '\n')
323 i = i + 1
323 i = i + 1
324 return res
324 return res
325
325
326
326
327 #---------------------------------------------------------------------------
327 #---------------------------------------------------------------------------
328 # Module classes
328 # Module classes
329 class TBTools(object):
329 class TBTools(object):
330 """Basic tools used by all traceback printer classes."""
330 """Basic tools used by all traceback printer classes."""
331
331
332 # Number of frames to skip when reporting tracebacks
332 # Number of frames to skip when reporting tracebacks
333 tb_offset = 0
333 tb_offset = 0
334
334
335 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
335 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
336 # Whether to call the interactive pdb debugger after printing
336 # Whether to call the interactive pdb debugger after printing
337 # tracebacks or not
337 # tracebacks or not
338 self.call_pdb = call_pdb
338 self.call_pdb = call_pdb
339
339
340 # Output stream to write to. Note that we store the original value in
340 # Output stream to write to. Note that we store the original value in
341 # a private attribute and then make the public ostream a property, so
341 # a private attribute and then make the public ostream a property, so
342 # that we can delay accessing io.stdout until runtime. The way
342 # that we can delay accessing io.stdout until runtime. The way
343 # things are written now, the io.stdout object is dynamically managed
343 # things are written now, the io.stdout object is dynamically managed
344 # so a reference to it should NEVER be stored statically. This
344 # so a reference to it should NEVER be stored statically. This
345 # property approach confines this detail to a single location, and all
345 # property approach confines this detail to a single location, and all
346 # subclasses can simply access self.ostream for writing.
346 # subclasses can simply access self.ostream for writing.
347 self._ostream = ostream
347 self._ostream = ostream
348
348
349 # Create color table
349 # Create color table
350 self.color_scheme_table = exception_colors()
350 self.color_scheme_table = exception_colors()
351
351
352 self.set_colors(color_scheme)
352 self.set_colors(color_scheme)
353 self.old_scheme = color_scheme # save initial value for toggles
353 self.old_scheme = color_scheme # save initial value for toggles
354
354
355 if call_pdb:
355 if call_pdb:
356 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
356 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
357 else:
357 else:
358 self.pdb = None
358 self.pdb = None
359
359
360 def _get_ostream(self):
360 def _get_ostream(self):
361 """Output stream that exceptions are written to.
361 """Output stream that exceptions are written to.
362
362
363 Valid values are:
363 Valid values are:
364
364
365 - None: the default, which means that IPython will dynamically resolve
365 - None: the default, which means that IPython will dynamically resolve
366 to io.stdout. This ensures compatibility with most tools, including
366 to io.stdout. This ensures compatibility with most tools, including
367 Windows (where plain stdout doesn't recognize ANSI escapes).
367 Windows (where plain stdout doesn't recognize ANSI escapes).
368
368
369 - Any object with 'write' and 'flush' attributes.
369 - Any object with 'write' and 'flush' attributes.
370 """
370 """
371 return io.stdout if self._ostream is None else self._ostream
371 return io.stdout if self._ostream is None else self._ostream
372
372
373 def _set_ostream(self, val):
373 def _set_ostream(self, val):
374 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
374 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
375 self._ostream = val
375 self._ostream = val
376
376
377 ostream = property(_get_ostream, _set_ostream)
377 ostream = property(_get_ostream, _set_ostream)
378
378
379 def set_colors(self,*args,**kw):
379 def set_colors(self,*args,**kw):
380 """Shorthand access to the color table scheme selector method."""
380 """Shorthand access to the color table scheme selector method."""
381
381
382 # Set own color table
382 # Set own color table
383 self.color_scheme_table.set_active_scheme(*args,**kw)
383 self.color_scheme_table.set_active_scheme(*args,**kw)
384 # for convenience, set Colors to the active scheme
384 # for convenience, set Colors to the active scheme
385 self.Colors = self.color_scheme_table.active_colors
385 self.Colors = self.color_scheme_table.active_colors
386 # Also set colors of debugger
386 # Also set colors of debugger
387 if hasattr(self,'pdb') and self.pdb is not None:
387 if hasattr(self,'pdb') and self.pdb is not None:
388 self.pdb.set_colors(*args,**kw)
388 self.pdb.set_colors(*args,**kw)
389
389
390 def color_toggle(self):
390 def color_toggle(self):
391 """Toggle between the currently active color scheme and NoColor."""
391 """Toggle between the currently active color scheme and NoColor."""
392
392
393 if self.color_scheme_table.active_scheme_name == 'NoColor':
393 if self.color_scheme_table.active_scheme_name == 'NoColor':
394 self.color_scheme_table.set_active_scheme(self.old_scheme)
394 self.color_scheme_table.set_active_scheme(self.old_scheme)
395 self.Colors = self.color_scheme_table.active_colors
395 self.Colors = self.color_scheme_table.active_colors
396 else:
396 else:
397 self.old_scheme = self.color_scheme_table.active_scheme_name
397 self.old_scheme = self.color_scheme_table.active_scheme_name
398 self.color_scheme_table.set_active_scheme('NoColor')
398 self.color_scheme_table.set_active_scheme('NoColor')
399 self.Colors = self.color_scheme_table.active_colors
399 self.Colors = self.color_scheme_table.active_colors
400
400
401 def stb2text(self, stb):
401 def stb2text(self, stb):
402 """Convert a structured traceback (a list) to a string."""
402 """Convert a structured traceback (a list) to a string."""
403 return '\n'.join(stb)
403 return '\n'.join(stb)
404
404
405 def text(self, etype, value, tb, tb_offset=None, context=5):
405 def text(self, etype, value, tb, tb_offset=None, context=5):
406 """Return formatted traceback.
406 """Return formatted traceback.
407
407
408 Subclasses may override this if they add extra arguments.
408 Subclasses may override this if they add extra arguments.
409 """
409 """
410 tb_list = self.structured_traceback(etype, value, tb,
410 tb_list = self.structured_traceback(etype, value, tb,
411 tb_offset, context)
411 tb_offset, context)
412 return self.stb2text(tb_list)
412 return self.stb2text(tb_list)
413
413
414 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
414 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
415 context=5, mode=None):
415 context=5, mode=None):
416 """Return a list of traceback frames.
416 """Return a list of traceback frames.
417
417
418 Must be implemented by each class.
418 Must be implemented by each class.
419 """
419 """
420 raise NotImplementedError()
420 raise NotImplementedError()
421
421
422
422
423 #---------------------------------------------------------------------------
423 #---------------------------------------------------------------------------
424 class ListTB(TBTools):
424 class ListTB(TBTools):
425 """Print traceback information from a traceback list, with optional color.
425 """Print traceback information from a traceback list, with optional color.
426
426
427 Calling requires 3 arguments: (etype, evalue, elist)
427 Calling requires 3 arguments: (etype, evalue, elist)
428 as would be obtained by::
428 as would be obtained by::
429
429
430 etype, evalue, tb = sys.exc_info()
430 etype, evalue, tb = sys.exc_info()
431 if tb:
431 if tb:
432 elist = traceback.extract_tb(tb)
432 elist = traceback.extract_tb(tb)
433 else:
433 else:
434 elist = None
434 elist = None
435
435
436 It can thus be used by programs which need to process the traceback before
436 It can thus be used by programs which need to process the traceback before
437 printing (such as console replacements based on the code module from the
437 printing (such as console replacements based on the code module from the
438 standard library).
438 standard library).
439
439
440 Because they are meant to be called without a full traceback (only a
440 Because they are meant to be called without a full traceback (only a
441 list), instances of this class can't call the interactive pdb debugger."""
441 list), instances of this class can't call the interactive pdb debugger."""
442
442
443 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
443 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
444 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
444 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
445 ostream=ostream)
445 ostream=ostream)
446
446
447 def __call__(self, etype, value, elist):
447 def __call__(self, etype, value, elist):
448 self.ostream.flush()
448 self.ostream.flush()
449 self.ostream.write(self.text(etype, value, elist))
449 self.ostream.write(self.text(etype, value, elist))
450 self.ostream.write('\n')
450 self.ostream.write('\n')
451
451
452 def structured_traceback(self, etype, value, elist, tb_offset=None,
452 def structured_traceback(self, etype, value, elist, tb_offset=None,
453 context=5):
453 context=5):
454 """Return a color formatted string with the traceback info.
454 """Return a color formatted string with the traceback info.
455
455
456 Parameters
456 Parameters
457 ----------
457 ----------
458 etype : exception type
458 etype : exception type
459 Type of the exception raised.
459 Type of the exception raised.
460
460
461 value : object
461 value : object
462 Data stored in the exception
462 Data stored in the exception
463
463
464 elist : list
464 elist : list
465 List of frames, see class docstring for details.
465 List of frames, see class docstring for details.
466
466
467 tb_offset : int, optional
467 tb_offset : int, optional
468 Number of frames in the traceback to skip. If not given, the
468 Number of frames in the traceback to skip. If not given, the
469 instance value is used (set in constructor).
469 instance value is used (set in constructor).
470
470
471 context : int, optional
471 context : int, optional
472 Number of lines of context information to print.
472 Number of lines of context information to print.
473
473
474 Returns
474 Returns
475 -------
475 -------
476 String with formatted exception.
476 String with formatted exception.
477 """
477 """
478 tb_offset = self.tb_offset if tb_offset is None else tb_offset
478 tb_offset = self.tb_offset if tb_offset is None else tb_offset
479 Colors = self.Colors
479 Colors = self.Colors
480 out_list = []
480 out_list = []
481 if elist:
481 if elist:
482
482
483 if tb_offset and len(elist) > tb_offset:
483 if tb_offset and len(elist) > tb_offset:
484 elist = elist[tb_offset:]
484 elist = elist[tb_offset:]
485
485
486 out_list.append('Traceback %s(most recent call last)%s:' %
486 out_list.append('Traceback %s(most recent call last)%s:' %
487 (Colors.normalEm, Colors.Normal) + '\n')
487 (Colors.normalEm, Colors.Normal) + '\n')
488 out_list.extend(self._format_list(elist))
488 out_list.extend(self._format_list(elist))
489 # The exception info should be a single entry in the list.
489 # The exception info should be a single entry in the list.
490 lines = ''.join(self._format_exception_only(etype, value))
490 lines = ''.join(self._format_exception_only(etype, value))
491 out_list.append(lines)
491 out_list.append(lines)
492
492
493 # Note: this code originally read:
493 # Note: this code originally read:
494
494
495 ## for line in lines[:-1]:
495 ## for line in lines[:-1]:
496 ## out_list.append(" "+line)
496 ## out_list.append(" "+line)
497 ## out_list.append(lines[-1])
497 ## out_list.append(lines[-1])
498
498
499 # This means it was indenting everything but the last line by a little
499 # This means it was indenting everything but the last line by a little
500 # bit. I've disabled this for now, but if we see ugliness somewhre we
500 # bit. I've disabled this for now, but if we see ugliness somewhre we
501 # can restore it.
501 # can restore it.
502
502
503 return out_list
503 return out_list
504
504
505 def _format_list(self, extracted_list):
505 def _format_list(self, extracted_list):
506 """Format a list of traceback entry tuples for printing.
506 """Format a list of traceback entry tuples for printing.
507
507
508 Given a list of tuples as returned by extract_tb() or
508 Given a list of tuples as returned by extract_tb() or
509 extract_stack(), return a list of strings ready for printing.
509 extract_stack(), return a list of strings ready for printing.
510 Each string in the resulting list corresponds to the item with the
510 Each string in the resulting list corresponds to the item with the
511 same index in the argument list. Each string ends in a newline;
511 same index in the argument list. Each string ends in a newline;
512 the strings may contain internal newlines as well, for those items
512 the strings may contain internal newlines as well, for those items
513 whose source text line is not None.
513 whose source text line is not None.
514
514
515 Lifted almost verbatim from traceback.py
515 Lifted almost verbatim from traceback.py
516 """
516 """
517
517
518 Colors = self.Colors
518 Colors = self.Colors
519 list = []
519 list = []
520 for filename, lineno, name, line in extracted_list[:-1]:
520 for filename, lineno, name, line in extracted_list[:-1]:
521 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
521 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
522 (Colors.filename, filename, Colors.Normal,
522 (Colors.filename, filename, Colors.Normal,
523 Colors.lineno, lineno, Colors.Normal,
523 Colors.lineno, lineno, Colors.Normal,
524 Colors.name, name, Colors.Normal)
524 Colors.name, name, Colors.Normal)
525 if line:
525 if line:
526 item += ' %s\n' % line.strip()
526 item += ' %s\n' % line.strip()
527 list.append(item)
527 list.append(item)
528 # Emphasize the last entry
528 # Emphasize the last entry
529 filename, lineno, name, line = extracted_list[-1]
529 filename, lineno, name, line = extracted_list[-1]
530 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
530 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
531 (Colors.normalEm,
531 (Colors.normalEm,
532 Colors.filenameEm, filename, Colors.normalEm,
532 Colors.filenameEm, filename, Colors.normalEm,
533 Colors.linenoEm, lineno, Colors.normalEm,
533 Colors.linenoEm, lineno, Colors.normalEm,
534 Colors.nameEm, name, Colors.normalEm,
534 Colors.nameEm, name, Colors.normalEm,
535 Colors.Normal)
535 Colors.Normal)
536 if line:
536 if line:
537 item += '%s %s%s\n' % (Colors.line, line.strip(),
537 item += '%s %s%s\n' % (Colors.line, line.strip(),
538 Colors.Normal)
538 Colors.Normal)
539 list.append(item)
539 list.append(item)
540 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
540 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
541 return list
541 return list
542
542
543 def _format_exception_only(self, etype, value):
543 def _format_exception_only(self, etype, value):
544 """Format the exception part of a traceback.
544 """Format the exception part of a traceback.
545
545
546 The arguments are the exception type and value such as given by
546 The arguments are the exception type and value such as given by
547 sys.exc_info()[:2]. The return value is a list of strings, each ending
547 sys.exc_info()[:2]. The return value is a list of strings, each ending
548 in a newline. Normally, the list contains a single string; however,
548 in a newline. Normally, the list contains a single string; however,
549 for SyntaxError exceptions, it contains several lines that (when
549 for SyntaxError exceptions, it contains several lines that (when
550 printed) display detailed information about where the syntax error
550 printed) display detailed information about where the syntax error
551 occurred. The message indicating which exception occurred is the
551 occurred. The message indicating which exception occurred is the
552 always last string in the list.
552 always last string in the list.
553
553
554 Also lifted nearly verbatim from traceback.py
554 Also lifted nearly verbatim from traceback.py
555 """
555 """
556 have_filedata = False
556 have_filedata = False
557 Colors = self.Colors
557 Colors = self.Colors
558 list = []
558 list = []
559 stype = Colors.excName + etype.__name__ + Colors.Normal
559 stype = Colors.excName + etype.__name__ + Colors.Normal
560 if value is None:
560 if value is None:
561 # Not sure if this can still happen in Python 2.6 and above
561 # Not sure if this can still happen in Python 2.6 and above
562 list.append( py3compat.cast_unicode(stype) + '\n')
562 list.append( py3compat.cast_unicode(stype) + '\n')
563 else:
563 else:
564 if issubclass(etype, SyntaxError):
564 if issubclass(etype, SyntaxError):
565 have_filedata = True
565 have_filedata = True
566 #print 'filename is',filename # dbg
566 #print 'filename is',filename # dbg
567 if not value.filename: value.filename = "<string>"
567 if not value.filename: value.filename = "<string>"
568 if value.lineno:
568 if value.lineno:
569 lineno = value.lineno
569 lineno = value.lineno
570 textline = ulinecache.getline(value.filename, value.lineno)
570 textline = ulinecache.getline(value.filename, value.lineno)
571 else:
571 else:
572 lineno = 'unknown'
572 lineno = 'unknown'
573 textline = ''
573 textline = ''
574 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
574 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
575 (Colors.normalEm,
575 (Colors.normalEm,
576 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
576 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
577 Colors.linenoEm, lineno, Colors.Normal ))
577 Colors.linenoEm, lineno, Colors.Normal ))
578 if textline == '':
578 if textline == '':
579 textline = py3compat.cast_unicode(value.text, "utf-8")
579 textline = py3compat.cast_unicode(value.text, "utf-8")
580
580
581 if textline is not None:
581 if textline is not None:
582 i = 0
582 i = 0
583 while i < len(textline) and textline[i].isspace():
583 while i < len(textline) and textline[i].isspace():
584 i += 1
584 i += 1
585 list.append('%s %s%s\n' % (Colors.line,
585 list.append('%s %s%s\n' % (Colors.line,
586 textline.strip(),
586 textline.strip(),
587 Colors.Normal))
587 Colors.Normal))
588 if value.offset is not None:
588 if value.offset is not None:
589 s = ' '
589 s = ' '
590 for c in textline[i:value.offset-1]:
590 for c in textline[i:value.offset-1]:
591 if c.isspace():
591 if c.isspace():
592 s += c
592 s += c
593 else:
593 else:
594 s += ' '
594 s += ' '
595 list.append('%s%s^%s\n' % (Colors.caret, s,
595 list.append('%s%s^%s\n' % (Colors.caret, s,
596 Colors.Normal) )
596 Colors.Normal) )
597
597
598 try:
598 try:
599 s = value.msg
599 s = value.msg
600 except Exception:
600 except Exception:
601 s = self._some_str(value)
601 s = self._some_str(value)
602 if s:
602 if s:
603 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
603 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
604 Colors.Normal, s))
604 Colors.Normal, s))
605 else:
605 else:
606 list.append('%s\n' % str(stype))
606 list.append('%s\n' % str(stype))
607
607
608 # sync with user hooks
608 # sync with user hooks
609 if have_filedata:
609 if have_filedata:
610 ipinst = get_ipython()
610 ipinst = get_ipython()
611 if ipinst is not None:
611 if ipinst is not None:
612 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
612 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
613
613
614 return list
614 return list
615
615
616 def get_exception_only(self, etype, value):
616 def get_exception_only(self, etype, value):
617 """Only print the exception type and message, without a traceback.
617 """Only print the exception type and message, without a traceback.
618
618
619 Parameters
619 Parameters
620 ----------
620 ----------
621 etype : exception type
621 etype : exception type
622 value : exception value
622 value : exception value
623 """
623 """
624 return ListTB.structured_traceback(self, etype, value, [])
624 return ListTB.structured_traceback(self, etype, value, [])
625
625
626
626
627 def show_exception_only(self, etype, evalue):
627 def show_exception_only(self, etype, evalue):
628 """Only print the exception type and message, without a traceback.
628 """Only print the exception type and message, without a traceback.
629
629
630 Parameters
630 Parameters
631 ----------
631 ----------
632 etype : exception type
632 etype : exception type
633 value : exception value
633 value : exception value
634 """
634 """
635 # This method needs to use __call__ from *this* class, not the one from
635 # This method needs to use __call__ from *this* class, not the one from
636 # a subclass whose signature or behavior may be different
636 # a subclass whose signature or behavior may be different
637 ostream = self.ostream
637 ostream = self.ostream
638 ostream.flush()
638 ostream.flush()
639 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
639 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
640 ostream.flush()
640 ostream.flush()
641
641
642 def _some_str(self, value):
642 def _some_str(self, value):
643 # Lifted from traceback.py
643 # Lifted from traceback.py
644 try:
644 try:
645 return str(value)
645 return str(value)
646 except:
646 except:
647 return '<unprintable %s object>' % type(value).__name__
647 return '<unprintable %s object>' % type(value).__name__
648
648
649 #----------------------------------------------------------------------------
649 #----------------------------------------------------------------------------
650 class VerboseTB(TBTools):
650 class VerboseTB(TBTools):
651 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
651 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
652 of HTML. Requires inspect and pydoc. Crazy, man.
652 of HTML. Requires inspect and pydoc. Crazy, man.
653
653
654 Modified version which optionally strips the topmost entries from the
654 Modified version which optionally strips the topmost entries from the
655 traceback, to be used with alternate interpreters (because their own code
655 traceback, to be used with alternate interpreters (because their own code
656 would appear in the traceback)."""
656 would appear in the traceback)."""
657
657
658 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
658 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
659 tb_offset=0, long_header=False, include_vars=True,
659 tb_offset=0, long_header=False, include_vars=True,
660 check_cache=None):
660 check_cache=None):
661 """Specify traceback offset, headers and color scheme.
661 """Specify traceback offset, headers and color scheme.
662
662
663 Define how many frames to drop from the tracebacks. Calling it with
663 Define how many frames to drop from the tracebacks. Calling it with
664 tb_offset=1 allows use of this handler in interpreters which will have
664 tb_offset=1 allows use of this handler in interpreters which will have
665 their own code at the top of the traceback (VerboseTB will first
665 their own code at the top of the traceback (VerboseTB will first
666 remove that frame before printing the traceback info)."""
666 remove that frame before printing the traceback info)."""
667 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
667 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
668 ostream=ostream)
668 ostream=ostream)
669 self.tb_offset = tb_offset
669 self.tb_offset = tb_offset
670 self.long_header = long_header
670 self.long_header = long_header
671 self.include_vars = include_vars
671 self.include_vars = include_vars
672 # By default we use linecache.checkcache, but the user can provide a
672 # By default we use linecache.checkcache, but the user can provide a
673 # different check_cache implementation. This is used by the IPython
673 # different check_cache implementation. This is used by the IPython
674 # kernel to provide tracebacks for interactive code that is cached,
674 # kernel to provide tracebacks for interactive code that is cached,
675 # by a compiler instance that flushes the linecache but preserves its
675 # by a compiler instance that flushes the linecache but preserves its
676 # own code cache.
676 # own code cache.
677 if check_cache is None:
677 if check_cache is None:
678 check_cache = linecache.checkcache
678 check_cache = linecache.checkcache
679 self.check_cache = check_cache
679 self.check_cache = check_cache
680
680
681 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
681 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
682 context=5):
682 context=5):
683 """Return a nice text document describing the traceback."""
683 """Return a nice text document describing the traceback."""
684
684
685 tb_offset = self.tb_offset if tb_offset is None else tb_offset
685 tb_offset = self.tb_offset if tb_offset is None else tb_offset
686
686
687 # some locals
687 # some locals
688 try:
688 try:
689 etype = etype.__name__
689 etype = etype.__name__
690 except AttributeError:
690 except AttributeError:
691 pass
691 pass
692 Colors = self.Colors # just a shorthand + quicker name lookup
692 Colors = self.Colors # just a shorthand + quicker name lookup
693 ColorsNormal = Colors.Normal # used a lot
693 ColorsNormal = Colors.Normal # used a lot
694 col_scheme = self.color_scheme_table.active_scheme_name
694 col_scheme = self.color_scheme_table.active_scheme_name
695 indent = ' '*INDENT_SIZE
695 indent = ' '*INDENT_SIZE
696 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
696 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
697 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
697 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
698 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
698 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
699
699
700 # some internal-use functions
700 # some internal-use functions
701 def text_repr(value):
701 def text_repr(value):
702 """Hopefully pretty robust repr equivalent."""
702 """Hopefully pretty robust repr equivalent."""
703 # this is pretty horrible but should always return *something*
703 # this is pretty horrible but should always return *something*
704 try:
704 try:
705 return pydoc.text.repr(value)
705 return pydoc.text.repr(value)
706 except KeyboardInterrupt:
706 except KeyboardInterrupt:
707 raise
707 raise
708 except:
708 except:
709 try:
709 try:
710 return repr(value)
710 return repr(value)
711 except KeyboardInterrupt:
711 except KeyboardInterrupt:
712 raise
712 raise
713 except:
713 except:
714 try:
714 try:
715 # all still in an except block so we catch
715 # all still in an except block so we catch
716 # getattr raising
716 # getattr raising
717 name = getattr(value, '__name__', None)
717 name = getattr(value, '__name__', None)
718 if name:
718 if name:
719 # ick, recursion
719 # ick, recursion
720 return text_repr(name)
720 return text_repr(name)
721 klass = getattr(value, '__class__', None)
721 klass = getattr(value, '__class__', None)
722 if klass:
722 if klass:
723 return '%s instance' % text_repr(klass)
723 return '%s instance' % text_repr(klass)
724 except KeyboardInterrupt:
724 except KeyboardInterrupt:
725 raise
725 raise
726 except:
726 except:
727 return 'UNRECOVERABLE REPR FAILURE'
727 return 'UNRECOVERABLE REPR FAILURE'
728 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
728 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
729 def nullrepr(value, repr=text_repr): return ''
729 def nullrepr(value, repr=text_repr): return ''
730
730
731 # meat of the code begins
731 # meat of the code begins
732 try:
732 try:
733 etype = etype.__name__
733 etype = etype.__name__
734 except AttributeError:
734 except AttributeError:
735 pass
735 pass
736
736
737 if self.long_header:
737 if self.long_header:
738 # Header with the exception type, python version, and date
738 # Header with the exception type, python version, and date
739 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
739 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
740 date = time.ctime(time.time())
740 date = time.ctime(time.time())
741
741
742 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
742 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
743 exc, ' '*(75-len(str(etype))-len(pyver)),
743 exc, ' '*(75-len(str(etype))-len(pyver)),
744 pyver, date.rjust(75) )
744 pyver, date.rjust(75) )
745 head += "\nA problem occured executing Python code. Here is the sequence of function"\
745 head += "\nA problem occured executing Python code. Here is the sequence of function"\
746 "\ncalls leading up to the error, with the most recent (innermost) call last."
746 "\ncalls leading up to the error, with the most recent (innermost) call last."
747 else:
747 else:
748 # Simplified header
748 # Simplified header
749 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
749 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
750 'Traceback (most recent call last)'.\
750 'Traceback (most recent call last)'.\
751 rjust(75 - len(str(etype)) ) )
751 rjust(75 - len(str(etype)) ) )
752 frames = []
752 frames = []
753 # Flush cache before calling inspect. This helps alleviate some of the
753 # Flush cache before calling inspect. This helps alleviate some of the
754 # problems with python 2.3's inspect.py.
754 # problems with python 2.3's inspect.py.
755 ##self.check_cache()
755 ##self.check_cache()
756 # Drop topmost frames if requested
756 # Drop topmost frames if requested
757 try:
757 try:
758 # Try the default getinnerframes and Alex's: Alex's fixes some
758 # Try the default getinnerframes and Alex's: Alex's fixes some
759 # problems, but it generates empty tracebacks for console errors
759 # problems, but it generates empty tracebacks for console errors
760 # (5 blanks lines) where none should be returned.
760 # (5 blanks lines) where none should be returned.
761 #records = inspect.getinnerframes(etb, context)[tb_offset:]
761 #records = inspect.getinnerframes(etb, context)[tb_offset:]
762 #print 'python records:', records # dbg
762 #print 'python records:', records # dbg
763 records = _fixed_getinnerframes(etb, context, tb_offset)
763 records = _fixed_getinnerframes(etb, context, tb_offset)
764 #print 'alex records:', records # dbg
764 #print 'alex records:', records # dbg
765 except:
765 except:
766
766
767 # FIXME: I've been getting many crash reports from python 2.3
767 # FIXME: I've been getting many crash reports from python 2.3
768 # users, traceable to inspect.py. If I can find a small test-case
768 # users, traceable to inspect.py. If I can find a small test-case
769 # to reproduce this, I should either write a better workaround or
769 # to reproduce this, I should either write a better workaround or
770 # file a bug report against inspect (if that's the real problem).
770 # file a bug report against inspect (if that's the real problem).
771 # So far, I haven't been able to find an isolated example to
771 # So far, I haven't been able to find an isolated example to
772 # reproduce the problem.
772 # reproduce the problem.
773 inspect_error()
773 inspect_error()
774 traceback.print_exc(file=self.ostream)
774 traceback.print_exc(file=self.ostream)
775 info('\nUnfortunately, your original traceback can not be constructed.\n')
775 info('\nUnfortunately, your original traceback can not be constructed.\n')
776 return ''
776 return ''
777
777
778 # build some color string templates outside these nested loops
778 # build some color string templates outside these nested loops
779 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
779 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
780 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
780 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
781 ColorsNormal)
781 ColorsNormal)
782 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
782 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
783 (Colors.vName, Colors.valEm, ColorsNormal)
783 (Colors.vName, Colors.valEm, ColorsNormal)
784 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
784 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
785 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
785 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
786 Colors.vName, ColorsNormal)
786 Colors.vName, ColorsNormal)
787 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
787 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
788 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
788 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
789 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
789 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
790 ColorsNormal)
790 ColorsNormal)
791
791
792 # now, loop over all records printing context and info
792 # now, loop over all records printing context and info
793 abspath = os.path.abspath
793 abspath = os.path.abspath
794 for frame, file, lnum, func, lines, index in records:
794 for frame, file, lnum, func, lines, index in records:
795 #print '*** record:',file,lnum,func,lines,index # dbg
795 #print '*** record:',file,lnum,func,lines,index # dbg
796 if not file:
796 if not file:
797 file = '?'
797 file = '?'
798 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
798 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
799 # Guess that filenames like <string> aren't real filenames, so
799 # Guess that filenames like <string> aren't real filenames, so
800 # don't call abspath on them.
800 # don't call abspath on them.
801 try:
801 try:
802 file = abspath(file)
802 file = abspath(file)
803 except OSError:
803 except OSError:
804 # Not sure if this can still happen: abspath now works with
804 # Not sure if this can still happen: abspath now works with
805 # file names like <string>
805 # file names like <string>
806 pass
806 pass
807 file = py3compat.cast_unicode(file, util_path.fs_encoding)
807 file = py3compat.cast_unicode(file, util_path.fs_encoding)
808 link = tpl_link % file
808 link = tpl_link % file
809 args, varargs, varkw, locals = inspect.getargvalues(frame)
809 args, varargs, varkw, locals = inspect.getargvalues(frame)
810
810
811 if func == '?':
811 if func == '?':
812 call = ''
812 call = ''
813 else:
813 else:
814 # Decide whether to include variable details or not
814 # Decide whether to include variable details or not
815 var_repr = self.include_vars and eqrepr or nullrepr
815 var_repr = self.include_vars and eqrepr or nullrepr
816 try:
816 try:
817 call = tpl_call % (func,inspect.formatargvalues(args,
817 call = tpl_call % (func,inspect.formatargvalues(args,
818 varargs, varkw,
818 varargs, varkw,
819 locals,formatvalue=var_repr))
819 locals,formatvalue=var_repr))
820 except KeyError:
820 except KeyError:
821 # This happens in situations like errors inside generator
821 # This happens in situations like errors inside generator
822 # expressions, where local variables are listed in the
822 # expressions, where local variables are listed in the
823 # line, but can't be extracted from the frame. I'm not
823 # line, but can't be extracted from the frame. I'm not
824 # 100% sure this isn't actually a bug in inspect itself,
824 # 100% sure this isn't actually a bug in inspect itself,
825 # but since there's no info for us to compute with, the
825 # but since there's no info for us to compute with, the
826 # best we can do is report the failure and move on. Here
826 # best we can do is report the failure and move on. Here
827 # we must *not* call any traceback construction again,
827 # we must *not* call any traceback construction again,
828 # because that would mess up use of %debug later on. So we
828 # because that would mess up use of %debug later on. So we
829 # simply report the failure and move on. The only
829 # simply report the failure and move on. The only
830 # limitation will be that this frame won't have locals
830 # limitation will be that this frame won't have locals
831 # listed in the call signature. Quite subtle problem...
831 # listed in the call signature. Quite subtle problem...
832 # I can't think of a good way to validate this in a unit
832 # I can't think of a good way to validate this in a unit
833 # test, but running a script consisting of:
833 # test, but running a script consisting of:
834 # dict( (k,v.strip()) for (k,v) in range(10) )
834 # dict( (k,v.strip()) for (k,v) in range(10) )
835 # will illustrate the error, if this exception catch is
835 # will illustrate the error, if this exception catch is
836 # disabled.
836 # disabled.
837 call = tpl_call_fail % func
837 call = tpl_call_fail % func
838
838
839 # Don't attempt to tokenize binary files.
839 # Don't attempt to tokenize binary files.
840 if file.endswith(('.so', '.pyd', '.dll')):
840 if file.endswith(('.so', '.pyd', '.dll')):
841 frames.append('%s %s\n' % (link,call))
841 frames.append('%s %s\n' % (link,call))
842 continue
842 continue
843 elif file.endswith(('.pyc','.pyo')):
843 elif file.endswith(('.pyc','.pyo')):
844 # Look up the corresponding source file.
844 # Look up the corresponding source file.
845 file = openpy.source_from_cache(file)
845 file = openpy.source_from_cache(file)
846
846
847 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
847 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
848 line = getline(file, lnum[0])
848 line = getline(file, lnum[0])
849 lnum[0] += 1
849 lnum[0] += 1
850 return line
850 return line
851
851
852 # Build the list of names on this line of code where the exception
852 # Build the list of names on this line of code where the exception
853 # occurred.
853 # occurred.
854 try:
854 try:
855 names = []
855 names = []
856 name_cont = False
856 name_cont = False
857
857
858 for token_type, token, start, end, line in generate_tokens(linereader):
858 for token_type, token, start, end, line in generate_tokens(linereader):
859 # build composite names
859 # build composite names
860 if token_type == tokenize.NAME and token not in keyword.kwlist:
860 if token_type == tokenize.NAME and token not in keyword.kwlist:
861 if name_cont:
861 if name_cont:
862 # Continuation of a dotted name
862 # Continuation of a dotted name
863 try:
863 try:
864 names[-1].append(token)
864 names[-1].append(token)
865 except IndexError:
865 except IndexError:
866 names.append([token])
866 names.append([token])
867 name_cont = False
867 name_cont = False
868 else:
868 else:
869 # Regular new names. We append everything, the caller
869 # Regular new names. We append everything, the caller
870 # will be responsible for pruning the list later. It's
870 # will be responsible for pruning the list later. It's
871 # very tricky to try to prune as we go, b/c composite
871 # very tricky to try to prune as we go, b/c composite
872 # names can fool us. The pruning at the end is easy
872 # names can fool us. The pruning at the end is easy
873 # to do (or the caller can print a list with repeated
873 # to do (or the caller can print a list with repeated
874 # names if so desired.
874 # names if so desired.
875 names.append([token])
875 names.append([token])
876 elif token == '.':
876 elif token == '.':
877 name_cont = True
877 name_cont = True
878 elif token_type == tokenize.NEWLINE:
878 elif token_type == tokenize.NEWLINE:
879 break
879 break
880
880
881 except (IndexError, UnicodeDecodeError):
881 except (IndexError, UnicodeDecodeError):
882 # signals exit of tokenizer
882 # signals exit of tokenizer
883 pass
883 pass
884 except tokenize.TokenError as msg:
884 except tokenize.TokenError as msg:
885 _m = ("An unexpected error occurred while tokenizing input\n"
885 _m = ("An unexpected error occurred while tokenizing input\n"
886 "The following traceback may be corrupted or invalid\n"
886 "The following traceback may be corrupted or invalid\n"
887 "The error message is: %s\n" % msg)
887 "The error message is: %s\n" % msg)
888 error(_m)
888 error(_m)
889
889
890 # Join composite names (e.g. "dict.fromkeys")
890 # Join composite names (e.g. "dict.fromkeys")
891 names = ['.'.join(n) for n in names]
891 names = ['.'.join(n) for n in names]
892 # prune names list of duplicates, but keep the right order
892 # prune names list of duplicates, but keep the right order
893 unique_names = uniq_stable(names)
893 unique_names = uniq_stable(names)
894
894
895 # Start loop over vars
895 # Start loop over vars
896 lvals = []
896 lvals = []
897 if self.include_vars:
897 if self.include_vars:
898 for name_full in unique_names:
898 for name_full in unique_names:
899 name_base = name_full.split('.',1)[0]
899 name_base = name_full.split('.',1)[0]
900 if name_base in frame.f_code.co_varnames:
900 if name_base in frame.f_code.co_varnames:
901 if name_base in locals:
901 if name_base in locals:
902 try:
902 try:
903 value = repr(eval(name_full,locals))
903 value = repr(eval(name_full,locals))
904 except:
904 except:
905 value = undefined
905 value = undefined
906 else:
906 else:
907 value = undefined
907 value = undefined
908 name = tpl_local_var % name_full
908 name = tpl_local_var % name_full
909 else:
909 else:
910 if name_base in frame.f_globals:
910 if name_base in frame.f_globals:
911 try:
911 try:
912 value = repr(eval(name_full,frame.f_globals))
912 value = repr(eval(name_full,frame.f_globals))
913 except:
913 except:
914 value = undefined
914 value = undefined
915 else:
915 else:
916 value = undefined
916 value = undefined
917 name = tpl_global_var % name_full
917 name = tpl_global_var % name_full
918 lvals.append(tpl_name_val % (name,value))
918 lvals.append(tpl_name_val % (name,value))
919 if lvals:
919 if lvals:
920 lvals = '%s%s' % (indent,em_normal.join(lvals))
920 lvals = '%s%s' % (indent,em_normal.join(lvals))
921 else:
921 else:
922 lvals = ''
922 lvals = ''
923
923
924 level = '%s %s\n' % (link,call)
924 level = '%s %s\n' % (link,call)
925
925
926 if index is None:
926 if index is None:
927 frames.append(level)
927 frames.append(level)
928 else:
928 else:
929 frames.append('%s%s' % (level,''.join(
929 frames.append('%s%s' % (level,''.join(
930 _format_traceback_lines(lnum,index,lines,Colors,lvals,
930 _format_traceback_lines(lnum,index,lines,Colors,lvals,
931 col_scheme))))
931 col_scheme))))
932
932
933 # Get (safely) a string form of the exception info
933 # Get (safely) a string form of the exception info
934 try:
934 try:
935 etype_str,evalue_str = map(str,(etype,evalue))
935 etype_str,evalue_str = map(str,(etype,evalue))
936 except:
936 except:
937 # User exception is improperly defined.
937 # User exception is improperly defined.
938 etype,evalue = str,sys.exc_info()[:2]
938 etype,evalue = str,sys.exc_info()[:2]
939 etype_str,evalue_str = map(str,(etype,evalue))
939 etype_str,evalue_str = map(str,(etype,evalue))
940 # ... and format it
940 # ... and format it
941 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
941 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
942 ColorsNormal, py3compat.cast_unicode(evalue_str))]
942 ColorsNormal, py3compat.cast_unicode(evalue_str))]
943 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
943 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
944 try:
944 try:
945 names = [w for w in dir(evalue) if isinstance(w, basestring)]
945 names = [w for w in dir(evalue) if isinstance(w, basestring)]
946 except:
946 except:
947 # Every now and then, an object with funny inernals blows up
947 # Every now and then, an object with funny inernals blows up
948 # when dir() is called on it. We do the best we can to report
948 # when dir() is called on it. We do the best we can to report
949 # the problem and continue
949 # the problem and continue
950 _m = '%sException reporting error (object with broken dir())%s:'
950 _m = '%sException reporting error (object with broken dir())%s:'
951 exception.append(_m % (Colors.excName,ColorsNormal))
951 exception.append(_m % (Colors.excName,ColorsNormal))
952 etype_str,evalue_str = map(str,sys.exc_info()[:2])
952 etype_str,evalue_str = map(str,sys.exc_info()[:2])
953 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
953 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
954 ColorsNormal, py3compat.cast_unicode(evalue_str)))
954 ColorsNormal, py3compat.cast_unicode(evalue_str)))
955 names = []
955 names = []
956 for name in names:
956 for name in names:
957 value = text_repr(getattr(evalue, name))
957 value = text_repr(getattr(evalue, name))
958 exception.append('\n%s%s = %s' % (indent, name, value))
958 exception.append('\n%s%s = %s' % (indent, name, value))
959
959
960 # vds: >>
960 # vds: >>
961 if records:
961 if records:
962 filepath, lnum = records[-1][1:3]
962 filepath, lnum = records[-1][1:3]
963 #print "file:", str(file), "linenb", str(lnum) # dbg
963 #print "file:", str(file), "linenb", str(lnum) # dbg
964 filepath = os.path.abspath(filepath)
964 filepath = os.path.abspath(filepath)
965 ipinst = get_ipython()
965 ipinst = get_ipython()
966 if ipinst is not None:
966 if ipinst is not None:
967 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
967 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
968 # vds: <<
968 # vds: <<
969
969
970 # return all our info assembled as a single string
970 # return all our info assembled as a single string
971 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
971 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
972 return [head] + frames + [''.join(exception[0])]
972 return [head] + frames + [''.join(exception[0])]
973
973
974 def debugger(self,force=False):
974 def debugger(self,force=False):
975 """Call up the pdb debugger if desired, always clean up the tb
975 """Call up the pdb debugger if desired, always clean up the tb
976 reference.
976 reference.
977
977
978 Keywords:
978 Keywords:
979
979
980 - force(False): by default, this routine checks the instance call_pdb
980 - force(False): by default, this routine checks the instance call_pdb
981 flag and does not actually invoke the debugger if the flag is false.
981 flag and does not actually invoke the debugger if the flag is false.
982 The 'force' option forces the debugger to activate even if the flag
982 The 'force' option forces the debugger to activate even if the flag
983 is false.
983 is false.
984
984
985 If the call_pdb flag is set, the pdb interactive debugger is
985 If the call_pdb flag is set, the pdb interactive debugger is
986 invoked. In all cases, the self.tb reference to the current traceback
986 invoked. In all cases, the self.tb reference to the current traceback
987 is deleted to prevent lingering references which hamper memory
987 is deleted to prevent lingering references which hamper memory
988 management.
988 management.
989
989
990 Note that each call to pdb() does an 'import readline', so if your app
990 Note that each call to pdb() does an 'import readline', so if your app
991 requires a special setup for the readline completers, you'll have to
991 requires a special setup for the readline completers, you'll have to
992 fix that by hand after invoking the exception handler."""
992 fix that by hand after invoking the exception handler."""
993
993
994 if force or self.call_pdb:
994 if force or self.call_pdb:
995 if self.pdb is None:
995 if self.pdb is None:
996 self.pdb = debugger.Pdb(
996 self.pdb = debugger.Pdb(
997 self.color_scheme_table.active_scheme_name)
997 self.color_scheme_table.active_scheme_name)
998 # the system displayhook may have changed, restore the original
998 # the system displayhook may have changed, restore the original
999 # for pdb
999 # for pdb
1000 display_trap = DisplayTrap(hook=sys.__displayhook__)
1000 display_trap = DisplayTrap(hook=sys.__displayhook__)
1001 with display_trap:
1001 with display_trap:
1002 self.pdb.reset()
1002 self.pdb.reset()
1003 # Find the right frame so we don't pop up inside ipython itself
1003 # Find the right frame so we don't pop up inside ipython itself
1004 if hasattr(self,'tb') and self.tb is not None:
1004 if hasattr(self,'tb') and self.tb is not None:
1005 etb = self.tb
1005 etb = self.tb
1006 else:
1006 else:
1007 etb = self.tb = sys.last_traceback
1007 etb = self.tb = sys.last_traceback
1008 while self.tb is not None and self.tb.tb_next is not None:
1008 while self.tb is not None and self.tb.tb_next is not None:
1009 self.tb = self.tb.tb_next
1009 self.tb = self.tb.tb_next
1010 if etb and etb.tb_next:
1010 if etb and etb.tb_next:
1011 etb = etb.tb_next
1011 etb = etb.tb_next
1012 self.pdb.botframe = etb.tb_frame
1012 self.pdb.botframe = etb.tb_frame
1013 self.pdb.interaction(self.tb.tb_frame, self.tb)
1013 self.pdb.interaction(self.tb.tb_frame, self.tb)
1014
1014
1015 if hasattr(self,'tb'):
1015 if hasattr(self,'tb'):
1016 del self.tb
1016 del self.tb
1017
1017
1018 def handler(self, info=None):
1018 def handler(self, info=None):
1019 (etype, evalue, etb) = info or sys.exc_info()
1019 (etype, evalue, etb) = info or sys.exc_info()
1020 self.tb = etb
1020 self.tb = etb
1021 ostream = self.ostream
1021 ostream = self.ostream
1022 ostream.flush()
1022 ostream.flush()
1023 ostream.write(self.text(etype, evalue, etb))
1023 ostream.write(self.text(etype, evalue, etb))
1024 ostream.write('\n')
1024 ostream.write('\n')
1025 ostream.flush()
1025 ostream.flush()
1026
1026
1027 # Changed so an instance can just be called as VerboseTB_inst() and print
1027 # Changed so an instance can just be called as VerboseTB_inst() and print
1028 # out the right info on its own.
1028 # out the right info on its own.
1029 def __call__(self, etype=None, evalue=None, etb=None):
1029 def __call__(self, etype=None, evalue=None, etb=None):
1030 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1030 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1031 if etb is None:
1031 if etb is None:
1032 self.handler()
1032 self.handler()
1033 else:
1033 else:
1034 self.handler((etype, evalue, etb))
1034 self.handler((etype, evalue, etb))
1035 try:
1035 try:
1036 self.debugger()
1036 self.debugger()
1037 except KeyboardInterrupt:
1037 except KeyboardInterrupt:
1038 print "\nKeyboardInterrupt"
1038 print "\nKeyboardInterrupt"
1039
1039
1040 #----------------------------------------------------------------------------
1040 #----------------------------------------------------------------------------
1041 class FormattedTB(VerboseTB, ListTB):
1041 class FormattedTB(VerboseTB, ListTB):
1042 """Subclass ListTB but allow calling with a traceback.
1042 """Subclass ListTB but allow calling with a traceback.
1043
1043
1044 It can thus be used as a sys.excepthook for Python > 2.1.
1044 It can thus be used as a sys.excepthook for Python > 2.1.
1045
1045
1046 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1046 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1047
1047
1048 Allows a tb_offset to be specified. This is useful for situations where
1048 Allows a tb_offset to be specified. This is useful for situations where
1049 one needs to remove a number of topmost frames from the traceback (such as
1049 one needs to remove a number of topmost frames from the traceback (such as
1050 occurs with python programs that themselves execute other python code,
1050 occurs with python programs that themselves execute other python code,
1051 like Python shells). """
1051 like Python shells). """
1052
1052
1053 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1053 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1054 ostream=None,
1054 ostream=None,
1055 tb_offset=0, long_header=False, include_vars=False,
1055 tb_offset=0, long_header=False, include_vars=False,
1056 check_cache=None):
1056 check_cache=None):
1057
1057
1058 # NEVER change the order of this list. Put new modes at the end:
1058 # NEVER change the order of this list. Put new modes at the end:
1059 self.valid_modes = ['Plain','Context','Verbose']
1059 self.valid_modes = ['Plain','Context','Verbose']
1060 self.verbose_modes = self.valid_modes[1:3]
1060 self.verbose_modes = self.valid_modes[1:3]
1061
1061
1062 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1062 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1063 ostream=ostream, tb_offset=tb_offset,
1063 ostream=ostream, tb_offset=tb_offset,
1064 long_header=long_header, include_vars=include_vars,
1064 long_header=long_header, include_vars=include_vars,
1065 check_cache=check_cache)
1065 check_cache=check_cache)
1066
1066
1067 # Different types of tracebacks are joined with different separators to
1067 # Different types of tracebacks are joined with different separators to
1068 # form a single string. They are taken from this dict
1068 # form a single string. They are taken from this dict
1069 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1069 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1070 # set_mode also sets the tb_join_char attribute
1070 # set_mode also sets the tb_join_char attribute
1071 self.set_mode(mode)
1071 self.set_mode(mode)
1072
1072
1073 def _extract_tb(self,tb):
1073 def _extract_tb(self,tb):
1074 if tb:
1074 if tb:
1075 return traceback.extract_tb(tb)
1075 return traceback.extract_tb(tb)
1076 else:
1076 else:
1077 return None
1077 return None
1078
1078
1079 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1079 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1080 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1080 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1081 mode = self.mode
1081 mode = self.mode
1082 if mode in self.verbose_modes:
1082 if mode in self.verbose_modes:
1083 # Verbose modes need a full traceback
1083 # Verbose modes need a full traceback
1084 return VerboseTB.structured_traceback(
1084 return VerboseTB.structured_traceback(
1085 self, etype, value, tb, tb_offset, context
1085 self, etype, value, tb, tb_offset, context
1086 )
1086 )
1087 else:
1087 else:
1088 # We must check the source cache because otherwise we can print
1088 # We must check the source cache because otherwise we can print
1089 # out-of-date source code.
1089 # out-of-date source code.
1090 self.check_cache()
1090 self.check_cache()
1091 # Now we can extract and format the exception
1091 # Now we can extract and format the exception
1092 elist = self._extract_tb(tb)
1092 elist = self._extract_tb(tb)
1093 return ListTB.structured_traceback(
1093 return ListTB.structured_traceback(
1094 self, etype, value, elist, tb_offset, context
1094 self, etype, value, elist, tb_offset, context
1095 )
1095 )
1096
1096
1097 def stb2text(self, stb):
1097 def stb2text(self, stb):
1098 """Convert a structured traceback (a list) to a string."""
1098 """Convert a structured traceback (a list) to a string."""
1099 return self.tb_join_char.join(stb)
1099 return self.tb_join_char.join(stb)
1100
1100
1101
1101
1102 def set_mode(self,mode=None):
1102 def set_mode(self,mode=None):
1103 """Switch to the desired mode.
1103 """Switch to the desired mode.
1104
1104
1105 If mode is not specified, cycles through the available modes."""
1105 If mode is not specified, cycles through the available modes."""
1106
1106
1107 if not mode:
1107 if not mode:
1108 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1108 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1109 len(self.valid_modes)
1109 len(self.valid_modes)
1110 self.mode = self.valid_modes[new_idx]
1110 self.mode = self.valid_modes[new_idx]
1111 elif mode not in self.valid_modes:
1111 elif mode not in self.valid_modes:
1112 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1112 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1113 'Valid modes: '+str(self.valid_modes))
1113 'Valid modes: '+str(self.valid_modes))
1114 else:
1114 else:
1115 self.mode = mode
1115 self.mode = mode
1116 # include variable details only in 'Verbose' mode
1116 # include variable details only in 'Verbose' mode
1117 self.include_vars = (self.mode == self.valid_modes[2])
1117 self.include_vars = (self.mode == self.valid_modes[2])
1118 # Set the join character for generating text tracebacks
1118 # Set the join character for generating text tracebacks
1119 self.tb_join_char = self._join_chars[self.mode]
1119 self.tb_join_char = self._join_chars[self.mode]
1120
1120
1121 # some convenient shorcuts
1121 # some convenient shorcuts
1122 def plain(self):
1122 def plain(self):
1123 self.set_mode(self.valid_modes[0])
1123 self.set_mode(self.valid_modes[0])
1124
1124
1125 def context(self):
1125 def context(self):
1126 self.set_mode(self.valid_modes[1])
1126 self.set_mode(self.valid_modes[1])
1127
1127
1128 def verbose(self):
1128 def verbose(self):
1129 self.set_mode(self.valid_modes[2])
1129 self.set_mode(self.valid_modes[2])
1130
1130
1131 #----------------------------------------------------------------------------
1131 #----------------------------------------------------------------------------
1132 class AutoFormattedTB(FormattedTB):
1132 class AutoFormattedTB(FormattedTB):
1133 """A traceback printer which can be called on the fly.
1133 """A traceback printer which can be called on the fly.
1134
1134
1135 It will find out about exceptions by itself.
1135 It will find out about exceptions by itself.
1136
1136
1137 A brief example::
1137 A brief example::
1138
1138
1139 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1139 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1140 try:
1140 try:
1141 ...
1141 ...
1142 except:
1142 except:
1143 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1143 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1144 """
1144 """
1145
1145
1146 def __call__(self,etype=None,evalue=None,etb=None,
1146 def __call__(self,etype=None,evalue=None,etb=None,
1147 out=None,tb_offset=None):
1147 out=None,tb_offset=None):
1148 """Print out a formatted exception traceback.
1148 """Print out a formatted exception traceback.
1149
1149
1150 Optional arguments:
1150 Optional arguments:
1151 - out: an open file-like object to direct output to.
1151 - out: an open file-like object to direct output to.
1152
1152
1153 - tb_offset: the number of frames to skip over in the stack, on a
1153 - tb_offset: the number of frames to skip over in the stack, on a
1154 per-call basis (this overrides temporarily the instance's tb_offset
1154 per-call basis (this overrides temporarily the instance's tb_offset
1155 given at initialization time. """
1155 given at initialization time. """
1156
1156
1157
1157
1158 if out is None:
1158 if out is None:
1159 out = self.ostream
1159 out = self.ostream
1160 out.flush()
1160 out.flush()
1161 out.write(self.text(etype, evalue, etb, tb_offset))
1161 out.write(self.text(etype, evalue, etb, tb_offset))
1162 out.write('\n')
1162 out.write('\n')
1163 out.flush()
1163 out.flush()
1164 # FIXME: we should remove the auto pdb behavior from here and leave
1164 # FIXME: we should remove the auto pdb behavior from here and leave
1165 # that to the clients.
1165 # that to the clients.
1166 try:
1166 try:
1167 self.debugger()
1167 self.debugger()
1168 except KeyboardInterrupt:
1168 except KeyboardInterrupt:
1169 print "\nKeyboardInterrupt"
1169 print "\nKeyboardInterrupt"
1170
1170
1171 def structured_traceback(self, etype=None, value=None, tb=None,
1171 def structured_traceback(self, etype=None, value=None, tb=None,
1172 tb_offset=None, context=5):
1172 tb_offset=None, context=5):
1173 if etype is None:
1173 if etype is None:
1174 etype,value,tb = sys.exc_info()
1174 etype,value,tb = sys.exc_info()
1175 self.tb = tb
1175 self.tb = tb
1176 return FormattedTB.structured_traceback(
1176 return FormattedTB.structured_traceback(
1177 self, etype, value, tb, tb_offset, context)
1177 self, etype, value, tb, tb_offset, context)
1178
1178
1179 #---------------------------------------------------------------------------
1179 #---------------------------------------------------------------------------
1180
1180
1181 # A simple class to preserve Nathan's original functionality.
1181 # A simple class to preserve Nathan's original functionality.
1182 class ColorTB(FormattedTB):
1182 class ColorTB(FormattedTB):
1183 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1183 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1184 def __init__(self,color_scheme='Linux',call_pdb=0):
1184 def __init__(self,color_scheme='Linux',call_pdb=0):
1185 FormattedTB.__init__(self,color_scheme=color_scheme,
1185 FormattedTB.__init__(self,color_scheme=color_scheme,
1186 call_pdb=call_pdb)
1186 call_pdb=call_pdb)
1187
1187
1188
1188
1189 class SyntaxTB(ListTB):
1189 class SyntaxTB(ListTB):
1190 """Extension which holds some state: the last exception value"""
1190 """Extension which holds some state: the last exception value"""
1191
1191
1192 def __init__(self,color_scheme = 'NoColor'):
1192 def __init__(self,color_scheme = 'NoColor'):
1193 ListTB.__init__(self,color_scheme)
1193 ListTB.__init__(self,color_scheme)
1194 self.last_syntax_error = None
1194 self.last_syntax_error = None
1195
1195
1196 def __call__(self, etype, value, elist):
1196 def __call__(self, etype, value, elist):
1197 self.last_syntax_error = value
1197 self.last_syntax_error = value
1198 ListTB.__call__(self,etype,value,elist)
1198 ListTB.__call__(self,etype,value,elist)
1199
1199
1200 def structured_traceback(self, etype, value, elist, tb_offset=None,
1200 def structured_traceback(self, etype, value, elist, tb_offset=None,
1201 context=5):
1201 context=5):
1202 # If the source file has been edited, the line in the syntax error can
1202 # If the source file has been edited, the line in the syntax error can
1203 # be wrong (retrieved from an outdated cache). This replaces it with
1203 # be wrong (retrieved from an outdated cache). This replaces it with
1204 # the current value.
1204 # the current value.
1205 if isinstance(value.filename, py3compat.string_types) \
1205 if isinstance(value, SyntaxError) \
1206 and isinstance(value.filename, py3compat.string_types) \
1206 and isinstance(value.lineno, int):
1207 and isinstance(value.lineno, int):
1207 linecache.checkcache(value.filename)
1208 linecache.checkcache(value.filename)
1208 newtext = ulinecache.getline(value.filename, value.lineno)
1209 newtext = ulinecache.getline(value.filename, value.lineno)
1209 if newtext:
1210 if newtext:
1210 value.text = newtext
1211 value.text = newtext
1211 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1212 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1212 tb_offset=tb_offset, context=context)
1213 tb_offset=tb_offset, context=context)
1213
1214
1214 def clear_err_state(self):
1215 def clear_err_state(self):
1215 """Return the current error state and clear it"""
1216 """Return the current error state and clear it"""
1216 e = self.last_syntax_error
1217 e = self.last_syntax_error
1217 self.last_syntax_error = None
1218 self.last_syntax_error = None
1218 return e
1219 return e
1219
1220
1220 def stb2text(self, stb):
1221 def stb2text(self, stb):
1221 """Convert a structured traceback (a list) to a string."""
1222 """Convert a structured traceback (a list) to a string."""
1222 return ''.join(stb)
1223 return ''.join(stb)
1223
1224
1224
1225
1225 #----------------------------------------------------------------------------
1226 #----------------------------------------------------------------------------
1226 # module testing (minimal)
1227 # module testing (minimal)
1227 if __name__ == "__main__":
1228 if __name__ == "__main__":
1228 def spam(c, d_e):
1229 def spam(c, d_e):
1229 (d, e) = d_e
1230 (d, e) = d_e
1230 x = c + d
1231 x = c + d
1231 y = c * d
1232 y = c * d
1232 foo(x, y)
1233 foo(x, y)
1233
1234
1234 def foo(a, b, bar=1):
1235 def foo(a, b, bar=1):
1235 eggs(a, b + bar)
1236 eggs(a, b + bar)
1236
1237
1237 def eggs(f, g, z=globals()):
1238 def eggs(f, g, z=globals()):
1238 h = f + g
1239 h = f + g
1239 i = f - g
1240 i = f - g
1240 return h / i
1241 return h / i
1241
1242
1242 print ''
1243 print ''
1243 print '*** Before ***'
1244 print '*** Before ***'
1244 try:
1245 try:
1245 print spam(1, (2, 3))
1246 print spam(1, (2, 3))
1246 except:
1247 except:
1247 traceback.print_exc()
1248 traceback.print_exc()
1248 print ''
1249 print ''
1249
1250
1250 handler = ColorTB()
1251 handler = ColorTB()
1251 print '*** ColorTB ***'
1252 print '*** ColorTB ***'
1252 try:
1253 try:
1253 print spam(1, (2, 3))
1254 print spam(1, (2, 3))
1254 except:
1255 except:
1255 handler(*sys.exc_info())
1256 handler(*sys.exc_info())
1256 print ''
1257 print ''
1257
1258
1258 handler = VerboseTB()
1259 handler = VerboseTB()
1259 print '*** VerboseTB ***'
1260 print '*** VerboseTB ***'
1260 try:
1261 try:
1261 print spam(1, (2, 3))
1262 print spam(1, (2, 3))
1262 except:
1263 except:
1263 handler(*sys.exc_info())
1264 handler(*sys.exc_info())
1264 print ''
1265 print ''
1265
1266
General Comments 0
You need to be logged in to leave comments. Login now