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