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