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