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