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