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