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