##// END OF EJS Templates
Adding value.text fallback if ulinecache returns ''
Jörgen Stenarson -
Show More
@@ -1,1235 +1,1237 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultratb.py -- Spice up your tracebacks!
3 ultratb.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultratb
12 import sys,ultratb
13 sys.excepthook = ultratb.ColorTB()
13 sys.excepthook = ultratb.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultratb
40 import sys,ultratb
41 sys.excepthook = ultratb.VerboseTB()
41 sys.excepthook = ultratb.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62 """
62 """
63
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 == '':
565 textline = py3compat.cast_unicode(value.text, "utf-8")
564
566
565 if textline is not None:
567 if textline is not None:
566 i = 0
568 i = 0
567 while i < len(textline) and textline[i].isspace():
569 while i < len(textline) and textline[i].isspace():
568 i += 1
570 i += 1
569 list.append('%s %s%s\n' % (Colors.line,
571 list.append('%s %s%s\n' % (Colors.line,
570 textline.strip(),
572 textline.strip(),
571 Colors.Normal))
573 Colors.Normal))
572 if value.offset is not None:
574 if value.offset is not None:
573 s = ' '
575 s = ' '
574 for c in textline[i:value.offset-1]:
576 for c in textline[i:value.offset-1]:
575 if c.isspace():
577 if c.isspace():
576 s += c
578 s += c
577 else:
579 else:
578 s += ' '
580 s += ' '
579 list.append('%s%s^%s\n' % (Colors.caret, s,
581 list.append('%s%s^%s\n' % (Colors.caret, s,
580 Colors.Normal) )
582 Colors.Normal) )
581
583
582 try:
584 try:
583 s = value.msg
585 s = value.msg
584 except Exception:
586 except Exception:
585 s = self._some_str(value)
587 s = self._some_str(value)
586 if s:
588 if s:
587 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
589 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
588 Colors.Normal, s))
590 Colors.Normal, s))
589 else:
591 else:
590 list.append('%s\n' % str(stype))
592 list.append('%s\n' % str(stype))
591
593
592 # sync with user hooks
594 # sync with user hooks
593 if have_filedata:
595 if have_filedata:
594 ipinst = ipapi.get()
596 ipinst = ipapi.get()
595 if ipinst is not None:
597 if ipinst is not None:
596 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
598 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
597
599
598 return list
600 return list
599
601
600 def get_exception_only(self, etype, value):
602 def get_exception_only(self, etype, value):
601 """Only print the exception type and message, without a traceback.
603 """Only print the exception type and message, without a traceback.
602
604
603 Parameters
605 Parameters
604 ----------
606 ----------
605 etype : exception type
607 etype : exception type
606 value : exception value
608 value : exception value
607 """
609 """
608 return ListTB.structured_traceback(self, etype, value, [])
610 return ListTB.structured_traceback(self, etype, value, [])
609
611
610
612
611 def show_exception_only(self, etype, evalue):
613 def show_exception_only(self, etype, evalue):
612 """Only print the exception type and message, without a traceback.
614 """Only print the exception type and message, without a traceback.
613
615
614 Parameters
616 Parameters
615 ----------
617 ----------
616 etype : exception type
618 etype : exception type
617 value : exception value
619 value : exception value
618 """
620 """
619 # 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
620 # a subclass whose signature or behavior may be different
622 # a subclass whose signature or behavior may be different
621 ostream = self.ostream
623 ostream = self.ostream
622 ostream.flush()
624 ostream.flush()
623 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
625 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
624 ostream.flush()
626 ostream.flush()
625
627
626 def _some_str(self, value):
628 def _some_str(self, value):
627 # Lifted from traceback.py
629 # Lifted from traceback.py
628 try:
630 try:
629 return str(value)
631 return str(value)
630 except:
632 except:
631 return '<unprintable %s object>' % type(value).__name__
633 return '<unprintable %s object>' % type(value).__name__
632
634
633 #----------------------------------------------------------------------------
635 #----------------------------------------------------------------------------
634 class VerboseTB(TBTools):
636 class VerboseTB(TBTools):
635 """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
636 of HTML. Requires inspect and pydoc. Crazy, man.
638 of HTML. Requires inspect and pydoc. Crazy, man.
637
639
638 Modified version which optionally strips the topmost entries from the
640 Modified version which optionally strips the topmost entries from the
639 traceback, to be used with alternate interpreters (because their own code
641 traceback, to be used with alternate interpreters (because their own code
640 would appear in the traceback)."""
642 would appear in the traceback)."""
641
643
642 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
644 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
643 tb_offset=0, long_header=False, include_vars=True,
645 tb_offset=0, long_header=False, include_vars=True,
644 check_cache=None):
646 check_cache=None):
645 """Specify traceback offset, headers and color scheme.
647 """Specify traceback offset, headers and color scheme.
646
648
647 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
648 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
649 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
650 remove that frame before printing the traceback info)."""
652 remove that frame before printing the traceback info)."""
651 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
653 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
652 ostream=ostream)
654 ostream=ostream)
653 self.tb_offset = tb_offset
655 self.tb_offset = tb_offset
654 self.long_header = long_header
656 self.long_header = long_header
655 self.include_vars = include_vars
657 self.include_vars = include_vars
656 # 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
657 # different check_cache implementation. This is used by the IPython
659 # different check_cache implementation. This is used by the IPython
658 # kernel to provide tracebacks for interactive code that is cached,
660 # kernel to provide tracebacks for interactive code that is cached,
659 # by a compiler instance that flushes the linecache but preserves its
661 # by a compiler instance that flushes the linecache but preserves its
660 # own code cache.
662 # own code cache.
661 if check_cache is None:
663 if check_cache is None:
662 check_cache = linecache.checkcache
664 check_cache = linecache.checkcache
663 self.check_cache = check_cache
665 self.check_cache = check_cache
664
666
665 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
667 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
666 context=5):
668 context=5):
667 """Return a nice text document describing the traceback."""
669 """Return a nice text document describing the traceback."""
668
670
669 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
670
672
671 # some locals
673 # some locals
672 try:
674 try:
673 etype = etype.__name__
675 etype = etype.__name__
674 except AttributeError:
676 except AttributeError:
675 pass
677 pass
676 Colors = self.Colors # just a shorthand + quicker name lookup
678 Colors = self.Colors # just a shorthand + quicker name lookup
677 ColorsNormal = Colors.Normal # used a lot
679 ColorsNormal = Colors.Normal # used a lot
678 col_scheme = self.color_scheme_table.active_scheme_name
680 col_scheme = self.color_scheme_table.active_scheme_name
679 indent = ' '*INDENT_SIZE
681 indent = ' '*INDENT_SIZE
680 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
682 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
681 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
683 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
682 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
684 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
683
685
684 # some internal-use functions
686 # some internal-use functions
685 def text_repr(value):
687 def text_repr(value):
686 """Hopefully pretty robust repr equivalent."""
688 """Hopefully pretty robust repr equivalent."""
687 # this is pretty horrible but should always return *something*
689 # this is pretty horrible but should always return *something*
688 try:
690 try:
689 return pydoc.text.repr(value)
691 return pydoc.text.repr(value)
690 except KeyboardInterrupt:
692 except KeyboardInterrupt:
691 raise
693 raise
692 except:
694 except:
693 try:
695 try:
694 return repr(value)
696 return repr(value)
695 except KeyboardInterrupt:
697 except KeyboardInterrupt:
696 raise
698 raise
697 except:
699 except:
698 try:
700 try:
699 # all still in an except block so we catch
701 # all still in an except block so we catch
700 # getattr raising
702 # getattr raising
701 name = getattr(value, '__name__', None)
703 name = getattr(value, '__name__', None)
702 if name:
704 if name:
703 # ick, recursion
705 # ick, recursion
704 return text_repr(name)
706 return text_repr(name)
705 klass = getattr(value, '__class__', None)
707 klass = getattr(value, '__class__', None)
706 if klass:
708 if klass:
707 return '%s instance' % text_repr(klass)
709 return '%s instance' % text_repr(klass)
708 except KeyboardInterrupt:
710 except KeyboardInterrupt:
709 raise
711 raise
710 except:
712 except:
711 return 'UNRECOVERABLE REPR FAILURE'
713 return 'UNRECOVERABLE REPR FAILURE'
712 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
714 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
713 def nullrepr(value, repr=text_repr): return ''
715 def nullrepr(value, repr=text_repr): return ''
714
716
715 # meat of the code begins
717 # meat of the code begins
716 try:
718 try:
717 etype = etype.__name__
719 etype = etype.__name__
718 except AttributeError:
720 except AttributeError:
719 pass
721 pass
720
722
721 if self.long_header:
723 if self.long_header:
722 # Header with the exception type, python version, and date
724 # Header with the exception type, python version, and date
723 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
725 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
724 date = time.ctime(time.time())
726 date = time.ctime(time.time())
725
727
726 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,
727 exc, ' '*(75-len(str(etype))-len(pyver)),
729 exc, ' '*(75-len(str(etype))-len(pyver)),
728 pyver, date.rjust(75) )
730 pyver, date.rjust(75) )
729 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"\
730 "\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."
731 else:
733 else:
732 # Simplified header
734 # Simplified header
733 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,
734 'Traceback (most recent call last)'.\
736 'Traceback (most recent call last)'.\
735 rjust(75 - len(str(etype)) ) )
737 rjust(75 - len(str(etype)) ) )
736 frames = []
738 frames = []
737 # Flush cache before calling inspect. This helps alleviate some of the
739 # Flush cache before calling inspect. This helps alleviate some of the
738 # problems with python 2.3's inspect.py.
740 # problems with python 2.3's inspect.py.
739 ##self.check_cache()
741 ##self.check_cache()
740 # Drop topmost frames if requested
742 # Drop topmost frames if requested
741 try:
743 try:
742 # Try the default getinnerframes and Alex's: Alex's fixes some
744 # Try the default getinnerframes and Alex's: Alex's fixes some
743 # problems, but it generates empty tracebacks for console errors
745 # problems, but it generates empty tracebacks for console errors
744 # (5 blanks lines) where none should be returned.
746 # (5 blanks lines) where none should be returned.
745 #records = inspect.getinnerframes(etb, context)[tb_offset:]
747 #records = inspect.getinnerframes(etb, context)[tb_offset:]
746 #print 'python records:', records # dbg
748 #print 'python records:', records # dbg
747 records = _fixed_getinnerframes(etb, context, tb_offset)
749 records = _fixed_getinnerframes(etb, context, tb_offset)
748 #print 'alex records:', records # dbg
750 #print 'alex records:', records # dbg
749 except:
751 except:
750
752
751 # 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
752 # 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
753 # to reproduce this, I should either write a better workaround or
755 # to reproduce this, I should either write a better workaround or
754 # 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).
755 # 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
756 # reproduce the problem.
758 # reproduce the problem.
757 inspect_error()
759 inspect_error()
758 traceback.print_exc(file=self.ostream)
760 traceback.print_exc(file=self.ostream)
759 info('\nUnfortunately, your original traceback can not be constructed.\n')
761 info('\nUnfortunately, your original traceback can not be constructed.\n')
760 return ''
762 return ''
761
763
762 # build some color string templates outside these nested loops
764 # build some color string templates outside these nested loops
763 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
765 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
764 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,
765 ColorsNormal)
767 ColorsNormal)
766 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
768 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
767 (Colors.vName, Colors.valEm, ColorsNormal)
769 (Colors.vName, Colors.valEm, ColorsNormal)
768 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
770 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
769 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
771 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
770 Colors.vName, ColorsNormal)
772 Colors.vName, ColorsNormal)
771 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
773 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
772 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
774 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
773 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,
774 ColorsNormal)
776 ColorsNormal)
775
777
776 # now, loop over all records printing context and info
778 # now, loop over all records printing context and info
777 abspath = os.path.abspath
779 abspath = os.path.abspath
778 for frame, file, lnum, func, lines, index in records:
780 for frame, file, lnum, func, lines, index in records:
779 #print '*** record:',file,lnum,func,lines,index # dbg
781 #print '*** record:',file,lnum,func,lines,index # dbg
780 if not file:
782 if not file:
781 file = '?'
783 file = '?'
782 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
784 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
783 # Guess that filenames like <string> aren't real filenames, so
785 # Guess that filenames like <string> aren't real filenames, so
784 # don't call abspath on them.
786 # don't call abspath on them.
785 try:
787 try:
786 file = abspath(file)
788 file = abspath(file)
787 except OSError:
789 except OSError:
788 # Not sure if this can still happen: abspath now works with
790 # Not sure if this can still happen: abspath now works with
789 # file names like <string>
791 # file names like <string>
790 pass
792 pass
791 file = py3compat.cast_unicode(file, util_path.fs_encoding)
793 file = py3compat.cast_unicode(file, util_path.fs_encoding)
792 link = tpl_link % file
794 link = tpl_link % file
793 args, varargs, varkw, locals = inspect.getargvalues(frame)
795 args, varargs, varkw, locals = inspect.getargvalues(frame)
794
796
795 if func == '?':
797 if func == '?':
796 call = ''
798 call = ''
797 else:
799 else:
798 # Decide whether to include variable details or not
800 # Decide whether to include variable details or not
799 var_repr = self.include_vars and eqrepr or nullrepr
801 var_repr = self.include_vars and eqrepr or nullrepr
800 try:
802 try:
801 call = tpl_call % (func,inspect.formatargvalues(args,
803 call = tpl_call % (func,inspect.formatargvalues(args,
802 varargs, varkw,
804 varargs, varkw,
803 locals,formatvalue=var_repr))
805 locals,formatvalue=var_repr))
804 except KeyError:
806 except KeyError:
805 # This happens in situations like errors inside generator
807 # This happens in situations like errors inside generator
806 # expressions, where local variables are listed in the
808 # expressions, where local variables are listed in the
807 # 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
808 # 100% sure this isn't actually a bug in inspect itself,
810 # 100% sure this isn't actually a bug in inspect itself,
809 # 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
810 # 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
811 # we must *not* call any traceback construction again,
813 # we must *not* call any traceback construction again,
812 # 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
813 # simply report the failure and move on. The only
815 # simply report the failure and move on. The only
814 # limitation will be that this frame won't have locals
816 # limitation will be that this frame won't have locals
815 # listed in the call signature. Quite subtle problem...
817 # listed in the call signature. Quite subtle problem...
816 # 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
817 # test, but running a script consisting of:
819 # test, but running a script consisting of:
818 # dict( (k,v.strip()) for (k,v) in range(10) )
820 # dict( (k,v.strip()) for (k,v) in range(10) )
819 # will illustrate the error, if this exception catch is
821 # will illustrate the error, if this exception catch is
820 # disabled.
822 # disabled.
821 call = tpl_call_fail % func
823 call = tpl_call_fail % func
822
824
823 # Don't attempt to tokenize binary files.
825 # Don't attempt to tokenize binary files.
824 if file.endswith(('.so', '.pyd', '.dll')):
826 if file.endswith(('.so', '.pyd', '.dll')):
825 frames.append('%s %s\n' % (link,call))
827 frames.append('%s %s\n' % (link,call))
826 continue
828 continue
827 elif file.endswith(('.pyc','.pyo')):
829 elif file.endswith(('.pyc','.pyo')):
828 # Look up the corresponding source file.
830 # Look up the corresponding source file.
829 file = pyfile.source_from_cache(file)
831 file = pyfile.source_from_cache(file)
830
832
831 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
833 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
832 line = getline(file, lnum[0])
834 line = getline(file, lnum[0])
833 lnum[0] += 1
835 lnum[0] += 1
834 return line
836 return line
835
837
836 # 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
837 # occurred.
839 # occurred.
838 try:
840 try:
839 names = []
841 names = []
840 name_cont = False
842 name_cont = False
841
843
842 for token_type, token, start, end, line in generate_tokens(linereader):
844 for token_type, token, start, end, line in generate_tokens(linereader):
843 # build composite names
845 # build composite names
844 if token_type == tokenize.NAME and token not in keyword.kwlist:
846 if token_type == tokenize.NAME and token not in keyword.kwlist:
845 if name_cont:
847 if name_cont:
846 # Continuation of a dotted name
848 # Continuation of a dotted name
847 try:
849 try:
848 names[-1].append(token)
850 names[-1].append(token)
849 except IndexError:
851 except IndexError:
850 names.append([token])
852 names.append([token])
851 name_cont = False
853 name_cont = False
852 else:
854 else:
853 # Regular new names. We append everything, the caller
855 # Regular new names. We append everything, the caller
854 # will be responsible for pruning the list later. It's
856 # will be responsible for pruning the list later. It's
855 # 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
856 # names can fool us. The pruning at the end is easy
858 # names can fool us. The pruning at the end is easy
857 # to do (or the caller can print a list with repeated
859 # to do (or the caller can print a list with repeated
858 # names if so desired.
860 # names if so desired.
859 names.append([token])
861 names.append([token])
860 elif token == '.':
862 elif token == '.':
861 name_cont = True
863 name_cont = True
862 elif token_type == tokenize.NEWLINE:
864 elif token_type == tokenize.NEWLINE:
863 break
865 break
864
866
865 except (IndexError, UnicodeDecodeError):
867 except (IndexError, UnicodeDecodeError):
866 # signals exit of tokenizer
868 # signals exit of tokenizer
867 pass
869 pass
868 except tokenize.TokenError as msg:
870 except tokenize.TokenError as msg:
869 _m = ("An unexpected error occurred while tokenizing input\n"
871 _m = ("An unexpected error occurred while tokenizing input\n"
870 "The following traceback may be corrupted or invalid\n"
872 "The following traceback may be corrupted or invalid\n"
871 "The error message is: %s\n" % msg)
873 "The error message is: %s\n" % msg)
872 error(_m)
874 error(_m)
873
875
874 # Join composite names (e.g. "dict.fromkeys")
876 # Join composite names (e.g. "dict.fromkeys")
875 names = ['.'.join(n) for n in names]
877 names = ['.'.join(n) for n in names]
876 # prune names list of duplicates, but keep the right order
878 # prune names list of duplicates, but keep the right order
877 unique_names = uniq_stable(names)
879 unique_names = uniq_stable(names)
878
880
879 # Start loop over vars
881 # Start loop over vars
880 lvals = []
882 lvals = []
881 if self.include_vars:
883 if self.include_vars:
882 for name_full in unique_names:
884 for name_full in unique_names:
883 name_base = name_full.split('.',1)[0]
885 name_base = name_full.split('.',1)[0]
884 if name_base in frame.f_code.co_varnames:
886 if name_base in frame.f_code.co_varnames:
885 if name_base in locals:
887 if name_base in locals:
886 try:
888 try:
887 value = repr(eval(name_full,locals))
889 value = repr(eval(name_full,locals))
888 except:
890 except:
889 value = undefined
891 value = undefined
890 else:
892 else:
891 value = undefined
893 value = undefined
892 name = tpl_local_var % name_full
894 name = tpl_local_var % name_full
893 else:
895 else:
894 if name_base in frame.f_globals:
896 if name_base in frame.f_globals:
895 try:
897 try:
896 value = repr(eval(name_full,frame.f_globals))
898 value = repr(eval(name_full,frame.f_globals))
897 except:
899 except:
898 value = undefined
900 value = undefined
899 else:
901 else:
900 value = undefined
902 value = undefined
901 name = tpl_global_var % name_full
903 name = tpl_global_var % name_full
902 lvals.append(tpl_name_val % (name,value))
904 lvals.append(tpl_name_val % (name,value))
903 if lvals:
905 if lvals:
904 lvals = '%s%s' % (indent,em_normal.join(lvals))
906 lvals = '%s%s' % (indent,em_normal.join(lvals))
905 else:
907 else:
906 lvals = ''
908 lvals = ''
907
909
908 level = '%s %s\n' % (link,call)
910 level = '%s %s\n' % (link,call)
909
911
910 if index is None:
912 if index is None:
911 frames.append(level)
913 frames.append(level)
912 else:
914 else:
913 frames.append('%s%s' % (level,''.join(
915 frames.append('%s%s' % (level,''.join(
914 _format_traceback_lines(lnum,index,lines,Colors,lvals,
916 _format_traceback_lines(lnum,index,lines,Colors,lvals,
915 col_scheme))))
917 col_scheme))))
916
918
917 # Get (safely) a string form of the exception info
919 # Get (safely) a string form of the exception info
918 try:
920 try:
919 etype_str,evalue_str = map(str,(etype,evalue))
921 etype_str,evalue_str = map(str,(etype,evalue))
920 except:
922 except:
921 # User exception is improperly defined.
923 # User exception is improperly defined.
922 etype,evalue = str,sys.exc_info()[:2]
924 etype,evalue = str,sys.exc_info()[:2]
923 etype_str,evalue_str = map(str,(etype,evalue))
925 etype_str,evalue_str = map(str,(etype,evalue))
924 # ... and format it
926 # ... and format it
925 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
927 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
926 ColorsNormal, evalue_str)]
928 ColorsNormal, evalue_str)]
927 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
929 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
928 try:
930 try:
929 names = [w for w in dir(evalue) if isinstance(w, basestring)]
931 names = [w for w in dir(evalue) if isinstance(w, basestring)]
930 except:
932 except:
931 # Every now and then, an object with funny inernals blows up
933 # Every now and then, an object with funny inernals blows up
932 # 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
933 # the problem and continue
935 # the problem and continue
934 _m = '%sException reporting error (object with broken dir())%s:'
936 _m = '%sException reporting error (object with broken dir())%s:'
935 exception.append(_m % (Colors.excName,ColorsNormal))
937 exception.append(_m % (Colors.excName,ColorsNormal))
936 etype_str,evalue_str = map(str,sys.exc_info()[:2])
938 etype_str,evalue_str = map(str,sys.exc_info()[:2])
937 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
939 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
938 ColorsNormal, evalue_str))
940 ColorsNormal, evalue_str))
939 names = []
941 names = []
940 for name in names:
942 for name in names:
941 value = text_repr(getattr(evalue, name))
943 value = text_repr(getattr(evalue, name))
942 exception.append('\n%s%s = %s' % (indent, name, value))
944 exception.append('\n%s%s = %s' % (indent, name, value))
943
945
944 # vds: >>
946 # vds: >>
945 if records:
947 if records:
946 filepath, lnum = records[-1][1:3]
948 filepath, lnum = records[-1][1:3]
947 #print "file:", str(file), "linenb", str(lnum) # dbg
949 #print "file:", str(file), "linenb", str(lnum) # dbg
948 filepath = os.path.abspath(filepath)
950 filepath = os.path.abspath(filepath)
949 ipinst = ipapi.get()
951 ipinst = ipapi.get()
950 if ipinst is not None:
952 if ipinst is not None:
951 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
953 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
952 # vds: <<
954 # vds: <<
953
955
954 # return all our info assembled as a single string
956 # return all our info assembled as a single string
955 # 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]) )
956 return [head] + frames + [''.join(exception[0])]
958 return [head] + frames + [''.join(exception[0])]
957
959
958 def debugger(self,force=False):
960 def debugger(self,force=False):
959 """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
960 reference.
962 reference.
961
963
962 Keywords:
964 Keywords:
963
965
964 - force(False): by default, this routine checks the instance call_pdb
966 - force(False): by default, this routine checks the instance call_pdb
965 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.
966 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
967 is false.
969 is false.
968
970
969 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
970 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
971 is deleted to prevent lingering references which hamper memory
973 is deleted to prevent lingering references which hamper memory
972 management.
974 management.
973
975
974 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
975 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
976 fix that by hand after invoking the exception handler."""
978 fix that by hand after invoking the exception handler."""
977
979
978 if force or self.call_pdb:
980 if force or self.call_pdb:
979 if self.pdb is None:
981 if self.pdb is None:
980 self.pdb = debugger.Pdb(
982 self.pdb = debugger.Pdb(
981 self.color_scheme_table.active_scheme_name)
983 self.color_scheme_table.active_scheme_name)
982 # the system displayhook may have changed, restore the original
984 # the system displayhook may have changed, restore the original
983 # for pdb
985 # for pdb
984 display_trap = DisplayTrap(hook=sys.__displayhook__)
986 display_trap = DisplayTrap(hook=sys.__displayhook__)
985 with display_trap:
987 with display_trap:
986 self.pdb.reset()
988 self.pdb.reset()
987 # 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
988 if hasattr(self,'tb') and self.tb is not None:
990 if hasattr(self,'tb') and self.tb is not None:
989 etb = self.tb
991 etb = self.tb
990 else:
992 else:
991 etb = self.tb = sys.last_traceback
993 etb = self.tb = sys.last_traceback
992 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:
993 self.tb = self.tb.tb_next
995 self.tb = self.tb.tb_next
994 if etb and etb.tb_next:
996 if etb and etb.tb_next:
995 etb = etb.tb_next
997 etb = etb.tb_next
996 self.pdb.botframe = etb.tb_frame
998 self.pdb.botframe = etb.tb_frame
997 self.pdb.interaction(self.tb.tb_frame, self.tb)
999 self.pdb.interaction(self.tb.tb_frame, self.tb)
998
1000
999 if hasattr(self,'tb'):
1001 if hasattr(self,'tb'):
1000 del self.tb
1002 del self.tb
1001
1003
1002 def handler(self, info=None):
1004 def handler(self, info=None):
1003 (etype, evalue, etb) = info or sys.exc_info()
1005 (etype, evalue, etb) = info or sys.exc_info()
1004 self.tb = etb
1006 self.tb = etb
1005 ostream = self.ostream
1007 ostream = self.ostream
1006 ostream.flush()
1008 ostream.flush()
1007 ostream.write(self.text(etype, evalue, etb))
1009 ostream.write(self.text(etype, evalue, etb))
1008 ostream.write('\n')
1010 ostream.write('\n')
1009 ostream.flush()
1011 ostream.flush()
1010
1012
1011 # 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
1012 # out the right info on its own.
1014 # out the right info on its own.
1013 def __call__(self, etype=None, evalue=None, etb=None):
1015 def __call__(self, etype=None, evalue=None, etb=None):
1014 """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)."""
1015 if etb is None:
1017 if etb is None:
1016 self.handler()
1018 self.handler()
1017 else:
1019 else:
1018 self.handler((etype, evalue, etb))
1020 self.handler((etype, evalue, etb))
1019 try:
1021 try:
1020 self.debugger()
1022 self.debugger()
1021 except KeyboardInterrupt:
1023 except KeyboardInterrupt:
1022 print "\nKeyboardInterrupt"
1024 print "\nKeyboardInterrupt"
1023
1025
1024 #----------------------------------------------------------------------------
1026 #----------------------------------------------------------------------------
1025 class FormattedTB(VerboseTB, ListTB):
1027 class FormattedTB(VerboseTB, ListTB):
1026 """Subclass ListTB but allow calling with a traceback.
1028 """Subclass ListTB but allow calling with a traceback.
1027
1029
1028 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.
1029
1031
1030 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1032 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1031
1033
1032 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
1033 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
1034 occurs with python programs that themselves execute other python code,
1036 occurs with python programs that themselves execute other python code,
1035 like Python shells). """
1037 like Python shells). """
1036
1038
1037 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1039 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1038 ostream=None,
1040 ostream=None,
1039 tb_offset=0, long_header=False, include_vars=False,
1041 tb_offset=0, long_header=False, include_vars=False,
1040 check_cache=None):
1042 check_cache=None):
1041
1043
1042 # 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:
1043 self.valid_modes = ['Plain','Context','Verbose']
1045 self.valid_modes = ['Plain','Context','Verbose']
1044 self.verbose_modes = self.valid_modes[1:3]
1046 self.verbose_modes = self.valid_modes[1:3]
1045
1047
1046 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1048 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1047 ostream=ostream, tb_offset=tb_offset,
1049 ostream=ostream, tb_offset=tb_offset,
1048 long_header=long_header, include_vars=include_vars,
1050 long_header=long_header, include_vars=include_vars,
1049 check_cache=check_cache)
1051 check_cache=check_cache)
1050
1052
1051 # Different types of tracebacks are joined with different separators to
1053 # Different types of tracebacks are joined with different separators to
1052 # form a single string. They are taken from this dict
1054 # form a single string. They are taken from this dict
1053 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1055 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1054 # set_mode also sets the tb_join_char attribute
1056 # set_mode also sets the tb_join_char attribute
1055 self.set_mode(mode)
1057 self.set_mode(mode)
1056
1058
1057 def _extract_tb(self,tb):
1059 def _extract_tb(self,tb):
1058 if tb:
1060 if tb:
1059 return traceback.extract_tb(tb)
1061 return traceback.extract_tb(tb)
1060 else:
1062 else:
1061 return None
1063 return None
1062
1064
1063 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):
1064 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
1065 mode = self.mode
1067 mode = self.mode
1066 if mode in self.verbose_modes:
1068 if mode in self.verbose_modes:
1067 # Verbose modes need a full traceback
1069 # Verbose modes need a full traceback
1068 return VerboseTB.structured_traceback(
1070 return VerboseTB.structured_traceback(
1069 self, etype, value, tb, tb_offset, context
1071 self, etype, value, tb, tb_offset, context
1070 )
1072 )
1071 else:
1073 else:
1072 # We must check the source cache because otherwise we can print
1074 # We must check the source cache because otherwise we can print
1073 # out-of-date source code.
1075 # out-of-date source code.
1074 self.check_cache()
1076 self.check_cache()
1075 # Now we can extract and format the exception
1077 # Now we can extract and format the exception
1076 elist = self._extract_tb(tb)
1078 elist = self._extract_tb(tb)
1077 return ListTB.structured_traceback(
1079 return ListTB.structured_traceback(
1078 self, etype, value, elist, tb_offset, context
1080 self, etype, value, elist, tb_offset, context
1079 )
1081 )
1080
1082
1081 def stb2text(self, stb):
1083 def stb2text(self, stb):
1082 """Convert a structured traceback (a list) to a string."""
1084 """Convert a structured traceback (a list) to a string."""
1083 return self.tb_join_char.join(stb)
1085 return self.tb_join_char.join(stb)
1084
1086
1085
1087
1086 def set_mode(self,mode=None):
1088 def set_mode(self,mode=None):
1087 """Switch to the desired mode.
1089 """Switch to the desired mode.
1088
1090
1089 If mode is not specified, cycles through the available modes."""
1091 If mode is not specified, cycles through the available modes."""
1090
1092
1091 if not mode:
1093 if not mode:
1092 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1094 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1093 len(self.valid_modes)
1095 len(self.valid_modes)
1094 self.mode = self.valid_modes[new_idx]
1096 self.mode = self.valid_modes[new_idx]
1095 elif mode not in self.valid_modes:
1097 elif mode not in self.valid_modes:
1096 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1098 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1097 'Valid modes: '+str(self.valid_modes))
1099 'Valid modes: '+str(self.valid_modes))
1098 else:
1100 else:
1099 self.mode = mode
1101 self.mode = mode
1100 # include variable details only in 'Verbose' mode
1102 # include variable details only in 'Verbose' mode
1101 self.include_vars = (self.mode == self.valid_modes[2])
1103 self.include_vars = (self.mode == self.valid_modes[2])
1102 # Set the join character for generating text tracebacks
1104 # Set the join character for generating text tracebacks
1103 self.tb_join_char = self._join_chars[self.mode]
1105 self.tb_join_char = self._join_chars[self.mode]
1104
1106
1105 # some convenient shorcuts
1107 # some convenient shorcuts
1106 def plain(self):
1108 def plain(self):
1107 self.set_mode(self.valid_modes[0])
1109 self.set_mode(self.valid_modes[0])
1108
1110
1109 def context(self):
1111 def context(self):
1110 self.set_mode(self.valid_modes[1])
1112 self.set_mode(self.valid_modes[1])
1111
1113
1112 def verbose(self):
1114 def verbose(self):
1113 self.set_mode(self.valid_modes[2])
1115 self.set_mode(self.valid_modes[2])
1114
1116
1115 #----------------------------------------------------------------------------
1117 #----------------------------------------------------------------------------
1116 class AutoFormattedTB(FormattedTB):
1118 class AutoFormattedTB(FormattedTB):
1117 """A traceback printer which can be called on the fly.
1119 """A traceback printer which can be called on the fly.
1118
1120
1119 It will find out about exceptions by itself.
1121 It will find out about exceptions by itself.
1120
1122
1121 A brief example:
1123 A brief example:
1122
1124
1123 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1125 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1124 try:
1126 try:
1125 ...
1127 ...
1126 except:
1128 except:
1127 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
1128 """
1130 """
1129
1131
1130 def __call__(self,etype=None,evalue=None,etb=None,
1132 def __call__(self,etype=None,evalue=None,etb=None,
1131 out=None,tb_offset=None):
1133 out=None,tb_offset=None):
1132 """Print out a formatted exception traceback.
1134 """Print out a formatted exception traceback.
1133
1135
1134 Optional arguments:
1136 Optional arguments:
1135 - out: an open file-like object to direct output to.
1137 - out: an open file-like object to direct output to.
1136
1138
1137 - 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
1138 per-call basis (this overrides temporarily the instance's tb_offset
1140 per-call basis (this overrides temporarily the instance's tb_offset
1139 given at initialization time. """
1141 given at initialization time. """
1140
1142
1141
1143
1142 if out is None:
1144 if out is None:
1143 out = self.ostream
1145 out = self.ostream
1144 out.flush()
1146 out.flush()
1145 out.write(self.text(etype, evalue, etb, tb_offset))
1147 out.write(self.text(etype, evalue, etb, tb_offset))
1146 out.write('\n')
1148 out.write('\n')
1147 out.flush()
1149 out.flush()
1148 # 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
1149 # that to the clients.
1151 # that to the clients.
1150 try:
1152 try:
1151 self.debugger()
1153 self.debugger()
1152 except KeyboardInterrupt:
1154 except KeyboardInterrupt:
1153 print "\nKeyboardInterrupt"
1155 print "\nKeyboardInterrupt"
1154
1156
1155 def structured_traceback(self, etype=None, value=None, tb=None,
1157 def structured_traceback(self, etype=None, value=None, tb=None,
1156 tb_offset=None, context=5):
1158 tb_offset=None, context=5):
1157 if etype is None:
1159 if etype is None:
1158 etype,value,tb = sys.exc_info()
1160 etype,value,tb = sys.exc_info()
1159 self.tb = tb
1161 self.tb = tb
1160 return FormattedTB.structured_traceback(
1162 return FormattedTB.structured_traceback(
1161 self, etype, value, tb, tb_offset, context)
1163 self, etype, value, tb, tb_offset, context)
1162
1164
1163 #---------------------------------------------------------------------------
1165 #---------------------------------------------------------------------------
1164
1166
1165 # A simple class to preserve Nathan's original functionality.
1167 # A simple class to preserve Nathan's original functionality.
1166 class ColorTB(FormattedTB):
1168 class ColorTB(FormattedTB):
1167 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1169 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1168 def __init__(self,color_scheme='Linux',call_pdb=0):
1170 def __init__(self,color_scheme='Linux',call_pdb=0):
1169 FormattedTB.__init__(self,color_scheme=color_scheme,
1171 FormattedTB.__init__(self,color_scheme=color_scheme,
1170 call_pdb=call_pdb)
1172 call_pdb=call_pdb)
1171
1173
1172
1174
1173 class SyntaxTB(ListTB):
1175 class SyntaxTB(ListTB):
1174 """Extension which holds some state: the last exception value"""
1176 """Extension which holds some state: the last exception value"""
1175
1177
1176 def __init__(self,color_scheme = 'NoColor'):
1178 def __init__(self,color_scheme = 'NoColor'):
1177 ListTB.__init__(self,color_scheme)
1179 ListTB.__init__(self,color_scheme)
1178 self.last_syntax_error = None
1180 self.last_syntax_error = None
1179
1181
1180 def __call__(self, etype, value, elist):
1182 def __call__(self, etype, value, elist):
1181 self.last_syntax_error = value
1183 self.last_syntax_error = value
1182 ListTB.__call__(self,etype,value,elist)
1184 ListTB.__call__(self,etype,value,elist)
1183
1185
1184 def clear_err_state(self):
1186 def clear_err_state(self):
1185 """Return the current error state and clear it"""
1187 """Return the current error state and clear it"""
1186 e = self.last_syntax_error
1188 e = self.last_syntax_error
1187 self.last_syntax_error = None
1189 self.last_syntax_error = None
1188 return e
1190 return e
1189
1191
1190 def stb2text(self, stb):
1192 def stb2text(self, stb):
1191 """Convert a structured traceback (a list) to a string."""
1193 """Convert a structured traceback (a list) to a string."""
1192 return ''.join(stb)
1194 return ''.join(stb)
1193
1195
1194
1196
1195 #----------------------------------------------------------------------------
1197 #----------------------------------------------------------------------------
1196 # module testing (minimal)
1198 # module testing (minimal)
1197 if __name__ == "__main__":
1199 if __name__ == "__main__":
1198 def spam(c, d_e):
1200 def spam(c, d_e):
1199 (d, e) = d_e
1201 (d, e) = d_e
1200 x = c + d
1202 x = c + d
1201 y = c * d
1203 y = c * d
1202 foo(x, y)
1204 foo(x, y)
1203
1205
1204 def foo(a, b, bar=1):
1206 def foo(a, b, bar=1):
1205 eggs(a, b + bar)
1207 eggs(a, b + bar)
1206
1208
1207 def eggs(f, g, z=globals()):
1209 def eggs(f, g, z=globals()):
1208 h = f + g
1210 h = f + g
1209 i = f - g
1211 i = f - g
1210 return h / i
1212 return h / i
1211
1213
1212 print ''
1214 print ''
1213 print '*** Before ***'
1215 print '*** Before ***'
1214 try:
1216 try:
1215 print spam(1, (2, 3))
1217 print spam(1, (2, 3))
1216 except:
1218 except:
1217 traceback.print_exc()
1219 traceback.print_exc()
1218 print ''
1220 print ''
1219
1221
1220 handler = ColorTB()
1222 handler = ColorTB()
1221 print '*** ColorTB ***'
1223 print '*** ColorTB ***'
1222 try:
1224 try:
1223 print spam(1, (2, 3))
1225 print spam(1, (2, 3))
1224 except:
1226 except:
1225 handler(*sys.exc_info())
1227 handler(*sys.exc_info())
1226 print ''
1228 print ''
1227
1229
1228 handler = VerboseTB()
1230 handler = VerboseTB()
1229 print '*** VerboseTB ***'
1231 print '*** VerboseTB ***'
1230 try:
1232 try:
1231 print spam(1, (2, 3))
1233 print spam(1, (2, 3))
1232 except:
1234 except:
1233 handler(*sys.exc_info())
1235 handler(*sys.exc_info())
1234 print ''
1236 print ''
1235
1237
General Comments 0
You need to be logged in to leave comments. Login now