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