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