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