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