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