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