##// END OF EJS Templates
Fix minor error that I saw in some odd cases, not sure how to test for it....
Fernando Perez -
Show More
@@ -1,1062 +1,1062 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
91
92 # IPython's own modules
92 # IPython's own modules
93 # Modified pdb which doesn't damage IPython's readline handling
93 # Modified pdb which doesn't damage IPython's readline handling
94 from IPython.utils import PyColorize
94 from IPython.utils import PyColorize
95 from IPython.core import debugger, ipapi
95 from IPython.core import debugger, ipapi
96 from IPython.core.display_trap import DisplayTrap
96 from IPython.core.display_trap import DisplayTrap
97 from IPython.utils.ipstruct import Struct
97 from IPython.utils.ipstruct import Struct
98 from IPython.core.excolors import exception_colors
98 from IPython.core.excolors import exception_colors
99 from IPython.utils.genutils import Term, uniq_stable, error, info
99 from IPython.utils.genutils import Term, uniq_stable, error, info
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:
313 class TBTools:
314 """Basic tools used by all traceback printer classes."""
314 """Basic tools used by all traceback printer classes."""
315
315
316 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
316 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
317 # Whether to call the interactive pdb debugger after printing
317 # Whether to call the interactive pdb debugger after printing
318 # tracebacks or not
318 # tracebacks or not
319 self.call_pdb = call_pdb
319 self.call_pdb = call_pdb
320
320
321 # Create color table
321 # Create color table
322 self.color_scheme_table = exception_colors()
322 self.color_scheme_table = exception_colors()
323
323
324 self.set_colors(color_scheme)
324 self.set_colors(color_scheme)
325 self.old_scheme = color_scheme # save initial value for toggles
325 self.old_scheme = color_scheme # save initial value for toggles
326
326
327 if call_pdb:
327 if call_pdb:
328 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
328 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
329 else:
329 else:
330 self.pdb = None
330 self.pdb = None
331
331
332 def set_colors(self,*args,**kw):
332 def set_colors(self,*args,**kw):
333 """Shorthand access to the color table scheme selector method."""
333 """Shorthand access to the color table scheme selector method."""
334
334
335 # Set own color table
335 # Set own color table
336 self.color_scheme_table.set_active_scheme(*args,**kw)
336 self.color_scheme_table.set_active_scheme(*args,**kw)
337 # for convenience, set Colors to the active scheme
337 # for convenience, set Colors to the active scheme
338 self.Colors = self.color_scheme_table.active_colors
338 self.Colors = self.color_scheme_table.active_colors
339 # Also set colors of debugger
339 # Also set colors of debugger
340 if hasattr(self,'pdb') and self.pdb is not None:
340 if hasattr(self,'pdb') and self.pdb is not None:
341 self.pdb.set_colors(*args,**kw)
341 self.pdb.set_colors(*args,**kw)
342
342
343 def color_toggle(self):
343 def color_toggle(self):
344 """Toggle between the currently active color scheme and NoColor."""
344 """Toggle between the currently active color scheme and NoColor."""
345
345
346 if self.color_scheme_table.active_scheme_name == 'NoColor':
346 if self.color_scheme_table.active_scheme_name == 'NoColor':
347 self.color_scheme_table.set_active_scheme(self.old_scheme)
347 self.color_scheme_table.set_active_scheme(self.old_scheme)
348 self.Colors = self.color_scheme_table.active_colors
348 self.Colors = self.color_scheme_table.active_colors
349 else:
349 else:
350 self.old_scheme = self.color_scheme_table.active_scheme_name
350 self.old_scheme = self.color_scheme_table.active_scheme_name
351 self.color_scheme_table.set_active_scheme('NoColor')
351 self.color_scheme_table.set_active_scheme('NoColor')
352 self.Colors = self.color_scheme_table.active_colors
352 self.Colors = self.color_scheme_table.active_colors
353
353
354 #---------------------------------------------------------------------------
354 #---------------------------------------------------------------------------
355 class ListTB(TBTools):
355 class ListTB(TBTools):
356 """Print traceback information from a traceback list, with optional color.
356 """Print traceback information from a traceback list, with optional color.
357
357
358 Calling: requires 3 arguments:
358 Calling: requires 3 arguments:
359 (etype, evalue, elist)
359 (etype, evalue, elist)
360 as would be obtained by:
360 as would be obtained by:
361 etype, evalue, tb = sys.exc_info()
361 etype, evalue, tb = sys.exc_info()
362 if tb:
362 if tb:
363 elist = traceback.extract_tb(tb)
363 elist = traceback.extract_tb(tb)
364 else:
364 else:
365 elist = None
365 elist = None
366
366
367 It can thus be used by programs which need to process the traceback before
367 It can thus be used by programs which need to process the traceback before
368 printing (such as console replacements based on the code module from the
368 printing (such as console replacements based on the code module from the
369 standard library).
369 standard library).
370
370
371 Because they are meant to be called without a full traceback (only a
371 Because they are meant to be called without a full traceback (only a
372 list), instances of this class can't call the interactive pdb debugger."""
372 list), instances of this class can't call the interactive pdb debugger."""
373
373
374 def __init__(self,color_scheme = 'NoColor'):
374 def __init__(self,color_scheme = 'NoColor'):
375 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
375 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
376
376
377 def __call__(self, etype, value, elist):
377 def __call__(self, etype, value, elist):
378 Term.cout.flush()
378 Term.cout.flush()
379 print >> Term.cerr, self.text(etype,value,elist)
379 print >> Term.cerr, self.text(etype,value,elist)
380 Term.cerr.flush()
380 Term.cerr.flush()
381
381
382 def text(self,etype, value, elist,context=5):
382 def text(self,etype, value, elist,context=5):
383 """Return a color formatted string with the traceback info."""
383 """Return a color formatted string with the traceback info."""
384
384
385 Colors = self.Colors
385 Colors = self.Colors
386 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
386 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
387 if elist:
387 if elist:
388 out_string.append('Traceback %s(most recent call last)%s:' % \
388 out_string.append('Traceback %s(most recent call last)%s:' % \
389 (Colors.normalEm, Colors.Normal) + '\n')
389 (Colors.normalEm, Colors.Normal) + '\n')
390 out_string.extend(self._format_list(elist))
390 out_string.extend(self._format_list(elist))
391 lines = self._format_exception_only(etype, value)
391 lines = self._format_exception_only(etype, value)
392 for line in lines[:-1]:
392 for line in lines[:-1]:
393 out_string.append(" "+line)
393 out_string.append(" "+line)
394 out_string.append(lines[-1])
394 out_string.append(lines[-1])
395 return ''.join(out_string)
395 return ''.join(out_string)
396
396
397 def _format_list(self, extracted_list):
397 def _format_list(self, extracted_list):
398 """Format a list of traceback entry tuples for printing.
398 """Format a list of traceback entry tuples for printing.
399
399
400 Given a list of tuples as returned by extract_tb() or
400 Given a list of tuples as returned by extract_tb() or
401 extract_stack(), return a list of strings ready for printing.
401 extract_stack(), return a list of strings ready for printing.
402 Each string in the resulting list corresponds to the item with the
402 Each string in the resulting list corresponds to the item with the
403 same index in the argument list. Each string ends in a newline;
403 same index in the argument list. Each string ends in a newline;
404 the strings may contain internal newlines as well, for those items
404 the strings may contain internal newlines as well, for those items
405 whose source text line is not None.
405 whose source text line is not None.
406
406
407 Lifted almost verbatim from traceback.py
407 Lifted almost verbatim from traceback.py
408 """
408 """
409
409
410 Colors = self.Colors
410 Colors = self.Colors
411 list = []
411 list = []
412 for filename, lineno, name, line in extracted_list[:-1]:
412 for filename, lineno, name, line in extracted_list[:-1]:
413 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
413 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
414 (Colors.filename, filename, Colors.Normal,
414 (Colors.filename, filename, Colors.Normal,
415 Colors.lineno, lineno, Colors.Normal,
415 Colors.lineno, lineno, Colors.Normal,
416 Colors.name, name, Colors.Normal)
416 Colors.name, name, Colors.Normal)
417 if line:
417 if line:
418 item = item + ' %s\n' % line.strip()
418 item = item + ' %s\n' % line.strip()
419 list.append(item)
419 list.append(item)
420 # Emphasize the last entry
420 # Emphasize the last entry
421 filename, lineno, name, line = extracted_list[-1]
421 filename, lineno, name, line = extracted_list[-1]
422 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
422 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
423 (Colors.normalEm,
423 (Colors.normalEm,
424 Colors.filenameEm, filename, Colors.normalEm,
424 Colors.filenameEm, filename, Colors.normalEm,
425 Colors.linenoEm, lineno, Colors.normalEm,
425 Colors.linenoEm, lineno, Colors.normalEm,
426 Colors.nameEm, name, Colors.normalEm,
426 Colors.nameEm, name, Colors.normalEm,
427 Colors.Normal)
427 Colors.Normal)
428 if line:
428 if line:
429 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
429 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
430 Colors.Normal)
430 Colors.Normal)
431 list.append(item)
431 list.append(item)
432 return list
432 return list
433
433
434 def _format_exception_only(self, etype, value):
434 def _format_exception_only(self, etype, value):
435 """Format the exception part of a traceback.
435 """Format the exception part of a traceback.
436
436
437 The arguments are the exception type and value such as given by
437 The arguments are the exception type and value such as given by
438 sys.exc_info()[:2]. The return value is a list of strings, each ending
438 sys.exc_info()[:2]. The return value is a list of strings, each ending
439 in a newline. Normally, the list contains a single string; however,
439 in a newline. Normally, the list contains a single string; however,
440 for SyntaxError exceptions, it contains several lines that (when
440 for SyntaxError exceptions, it contains several lines that (when
441 printed) display detailed information about where the syntax error
441 printed) display detailed information about where the syntax error
442 occurred. The message indicating which exception occurred is the
442 occurred. The message indicating which exception occurred is the
443 always last string in the list.
443 always last string in the list.
444
444
445 Also lifted nearly verbatim from traceback.py
445 Also lifted nearly verbatim from traceback.py
446 """
446 """
447
447
448 have_filedata = False
448 have_filedata = False
449 Colors = self.Colors
449 Colors = self.Colors
450 list = []
450 list = []
451 try:
451 try:
452 stype = Colors.excName + etype.__name__ + Colors.Normal
452 stype = Colors.excName + etype.__name__ + Colors.Normal
453 except AttributeError:
453 except AttributeError:
454 stype = etype # String exceptions don't get special coloring
454 stype = etype # String exceptions don't get special coloring
455 if value is None:
455 if value is None:
456 list.append( str(stype) + '\n')
456 list.append( str(stype) + '\n')
457 else:
457 else:
458 if etype is SyntaxError:
458 if etype is SyntaxError:
459 try:
459 try:
460 msg, (filename, lineno, offset, line) = value
460 msg, (filename, lineno, offset, line) = value
461 except:
461 except:
462 have_filedata = False
462 have_filedata = False
463 else:
463 else:
464 have_filedata = True
464 have_filedata = True
465 #print 'filename is',filename # dbg
465 #print 'filename is',filename # dbg
466 if not filename: filename = "<string>"
466 if not filename: filename = "<string>"
467 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
467 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 (Colors.normalEm,
468 (Colors.normalEm,
469 Colors.filenameEm, filename, Colors.normalEm,
469 Colors.filenameEm, filename, Colors.normalEm,
470 Colors.linenoEm, lineno, Colors.Normal ))
470 Colors.linenoEm, lineno, Colors.Normal ))
471 if line is not None:
471 if line is not None:
472 i = 0
472 i = 0
473 while i < len(line) and line[i].isspace():
473 while i < len(line) and line[i].isspace():
474 i = i+1
474 i = i+1
475 list.append('%s %s%s\n' % (Colors.line,
475 list.append('%s %s%s\n' % (Colors.line,
476 line.strip(),
476 line.strip(),
477 Colors.Normal))
477 Colors.Normal))
478 if offset is not None:
478 if offset is not None:
479 s = ' '
479 s = ' '
480 for c in line[i:offset-1]:
480 for c in line[i:offset-1]:
481 if c.isspace():
481 if c.isspace():
482 s = s + c
482 s = s + c
483 else:
483 else:
484 s = s + ' '
484 s = s + ' '
485 list.append('%s%s^%s\n' % (Colors.caret, s,
485 list.append('%s%s^%s\n' % (Colors.caret, s,
486 Colors.Normal) )
486 Colors.Normal) )
487 value = msg
487 value = msg
488 s = self._some_str(value)
488 s = self._some_str(value)
489 if s:
489 if s:
490 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
490 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
491 Colors.Normal, s))
491 Colors.Normal, s))
492 else:
492 else:
493 list.append('%s\n' % str(stype))
493 list.append('%s\n' % str(stype))
494
494
495 # vds:>>
495 # vds:>>
496 if have_filedata:
496 if have_filedata:
497 ipinst = ipapi.get()
497 ipinst = ipapi.get()
498 if ipinst is not None:
498 if ipinst is not None:
499 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
499 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
500 # vds:<<
500 # vds:<<
501
501
502 return list
502 return list
503
503
504 def _some_str(self, value):
504 def _some_str(self, value):
505 # Lifted from traceback.py
505 # Lifted from traceback.py
506 try:
506 try:
507 return str(value)
507 return str(value)
508 except:
508 except:
509 return '<unprintable %s object>' % type(value).__name__
509 return '<unprintable %s object>' % type(value).__name__
510
510
511 #----------------------------------------------------------------------------
511 #----------------------------------------------------------------------------
512 class VerboseTB(TBTools):
512 class VerboseTB(TBTools):
513 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
513 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
514 of HTML. Requires inspect and pydoc. Crazy, man.
514 of HTML. Requires inspect and pydoc. Crazy, man.
515
515
516 Modified version which optionally strips the topmost entries from the
516 Modified version which optionally strips the topmost entries from the
517 traceback, to be used with alternate interpreters (because their own code
517 traceback, to be used with alternate interpreters (because their own code
518 would appear in the traceback)."""
518 would appear in the traceback)."""
519
519
520 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
520 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
521 call_pdb = 0, include_vars=1):
521 call_pdb = 0, include_vars=1):
522 """Specify traceback offset, headers and color scheme.
522 """Specify traceback offset, headers and color scheme.
523
523
524 Define how many frames to drop from the tracebacks. Calling it with
524 Define how many frames to drop from the tracebacks. Calling it with
525 tb_offset=1 allows use of this handler in interpreters which will have
525 tb_offset=1 allows use of this handler in interpreters which will have
526 their own code at the top of the traceback (VerboseTB will first
526 their own code at the top of the traceback (VerboseTB will first
527 remove that frame before printing the traceback info)."""
527 remove that frame before printing the traceback info)."""
528 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
528 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
529 self.tb_offset = tb_offset
529 self.tb_offset = tb_offset
530 self.long_header = long_header
530 self.long_header = long_header
531 self.include_vars = include_vars
531 self.include_vars = include_vars
532
532
533 def text(self, etype, evalue, etb, context=5):
533 def text(self, etype, evalue, etb, context=5):
534 """Return a nice text document describing the traceback."""
534 """Return a nice text document describing the traceback."""
535
535
536 # some locals
536 # some locals
537 try:
537 try:
538 etype = etype.__name__
538 etype = etype.__name__
539 except AttributeError:
539 except AttributeError:
540 pass
540 pass
541 Colors = self.Colors # just a shorthand + quicker name lookup
541 Colors = self.Colors # just a shorthand + quicker name lookup
542 ColorsNormal = Colors.Normal # used a lot
542 ColorsNormal = Colors.Normal # used a lot
543 col_scheme = self.color_scheme_table.active_scheme_name
543 col_scheme = self.color_scheme_table.active_scheme_name
544 indent = ' '*INDENT_SIZE
544 indent = ' '*INDENT_SIZE
545 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
545 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
546 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
546 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
547 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
547 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
548
548
549 # some internal-use functions
549 # some internal-use functions
550 def text_repr(value):
550 def text_repr(value):
551 """Hopefully pretty robust repr equivalent."""
551 """Hopefully pretty robust repr equivalent."""
552 # this is pretty horrible but should always return *something*
552 # this is pretty horrible but should always return *something*
553 try:
553 try:
554 return pydoc.text.repr(value)
554 return pydoc.text.repr(value)
555 except KeyboardInterrupt:
555 except KeyboardInterrupt:
556 raise
556 raise
557 except:
557 except:
558 try:
558 try:
559 return repr(value)
559 return repr(value)
560 except KeyboardInterrupt:
560 except KeyboardInterrupt:
561 raise
561 raise
562 except:
562 except:
563 try:
563 try:
564 # all still in an except block so we catch
564 # all still in an except block so we catch
565 # getattr raising
565 # getattr raising
566 name = getattr(value, '__name__', None)
566 name = getattr(value, '__name__', None)
567 if name:
567 if name:
568 # ick, recursion
568 # ick, recursion
569 return text_repr(name)
569 return text_repr(name)
570 klass = getattr(value, '__class__', None)
570 klass = getattr(value, '__class__', None)
571 if klass:
571 if klass:
572 return '%s instance' % text_repr(klass)
572 return '%s instance' % text_repr(klass)
573 except KeyboardInterrupt:
573 except KeyboardInterrupt:
574 raise
574 raise
575 except:
575 except:
576 return 'UNRECOVERABLE REPR FAILURE'
576 return 'UNRECOVERABLE REPR FAILURE'
577 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
577 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
578 def nullrepr(value, repr=text_repr): return ''
578 def nullrepr(value, repr=text_repr): return ''
579
579
580 # meat of the code begins
580 # meat of the code begins
581 try:
581 try:
582 etype = etype.__name__
582 etype = etype.__name__
583 except AttributeError:
583 except AttributeError:
584 pass
584 pass
585
585
586 if self.long_header:
586 if self.long_header:
587 # Header with the exception type, python version, and date
587 # Header with the exception type, python version, and date
588 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
588 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
589 date = time.ctime(time.time())
589 date = time.ctime(time.time())
590
590
591 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
591 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
592 exc, ' '*(75-len(str(etype))-len(pyver)),
592 exc, ' '*(75-len(str(etype))-len(pyver)),
593 pyver, string.rjust(date, 75) )
593 pyver, string.rjust(date, 75) )
594 head += "\nA problem occured executing Python code. Here is the sequence of function"\
594 head += "\nA problem occured executing Python code. Here is the sequence of function"\
595 "\ncalls leading up to the error, with the most recent (innermost) call last."
595 "\ncalls leading up to the error, with the most recent (innermost) call last."
596 else:
596 else:
597 # Simplified header
597 # Simplified header
598 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
598 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
599 string.rjust('Traceback (most recent call last)',
599 string.rjust('Traceback (most recent call last)',
600 75 - len(str(etype)) ) )
600 75 - len(str(etype)) ) )
601 frames = []
601 frames = []
602 # Flush cache before calling inspect. This helps alleviate some of the
602 # Flush cache before calling inspect. This helps alleviate some of the
603 # problems with python 2.3's inspect.py.
603 # problems with python 2.3's inspect.py.
604 linecache.checkcache()
604 linecache.checkcache()
605 # Drop topmost frames if requested
605 # Drop topmost frames if requested
606 try:
606 try:
607 # Try the default getinnerframes and Alex's: Alex's fixes some
607 # Try the default getinnerframes and Alex's: Alex's fixes some
608 # problems, but it generates empty tracebacks for console errors
608 # problems, but it generates empty tracebacks for console errors
609 # (5 blanks lines) where none should be returned.
609 # (5 blanks lines) where none should be returned.
610 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
610 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
611 #print 'python records:', records # dbg
611 #print 'python records:', records # dbg
612 records = _fixed_getinnerframes(etb, context,self.tb_offset)
612 records = _fixed_getinnerframes(etb, context,self.tb_offset)
613 #print 'alex records:', records # dbg
613 #print 'alex records:', records # dbg
614 except:
614 except:
615
615
616 # FIXME: I've been getting many crash reports from python 2.3
616 # FIXME: I've been getting many crash reports from python 2.3
617 # users, traceable to inspect.py. If I can find a small test-case
617 # users, traceable to inspect.py. If I can find a small test-case
618 # to reproduce this, I should either write a better workaround or
618 # to reproduce this, I should either write a better workaround or
619 # file a bug report against inspect (if that's the real problem).
619 # file a bug report against inspect (if that's the real problem).
620 # So far, I haven't been able to find an isolated example to
620 # So far, I haven't been able to find an isolated example to
621 # reproduce the problem.
621 # reproduce the problem.
622 inspect_error()
622 inspect_error()
623 traceback.print_exc(file=Term.cerr)
623 traceback.print_exc(file=Term.cerr)
624 info('\nUnfortunately, your original traceback can not be constructed.\n')
624 info('\nUnfortunately, your original traceback can not be constructed.\n')
625 return ''
625 return ''
626
626
627 # build some color string templates outside these nested loops
627 # build some color string templates outside these nested loops
628 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
628 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
629 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
629 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
630 ColorsNormal)
630 ColorsNormal)
631 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
631 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
632 (Colors.vName, Colors.valEm, ColorsNormal)
632 (Colors.vName, Colors.valEm, ColorsNormal)
633 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
633 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
634 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
634 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
635 Colors.vName, ColorsNormal)
635 Colors.vName, ColorsNormal)
636 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
636 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
637 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
637 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
638 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
638 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
639 ColorsNormal)
639 ColorsNormal)
640
640
641 # now, loop over all records printing context and info
641 # now, loop over all records printing context and info
642 abspath = os.path.abspath
642 abspath = os.path.abspath
643 for frame, file, lnum, func, lines, index in records:
643 for frame, file, lnum, func, lines, index in records:
644 #print '*** record:',file,lnum,func,lines,index # dbg
644 #print '*** record:',file,lnum,func,lines,index # dbg
645 try:
645 try:
646 file = file and abspath(file) or '?'
646 file = file and abspath(file) or '?'
647 except OSError:
647 except OSError:
648 # if file is '<console>' or something not in the filesystem,
648 # if file is '<console>' or something not in the filesystem,
649 # the abspath call will throw an OSError. Just ignore it and
649 # the abspath call will throw an OSError. Just ignore it and
650 # keep the original file string.
650 # keep the original file string.
651 pass
651 pass
652 link = tpl_link % file
652 link = tpl_link % file
653 try:
653 try:
654 args, varargs, varkw, locals = inspect.getargvalues(frame)
654 args, varargs, varkw, locals = inspect.getargvalues(frame)
655 except:
655 except:
656 # This can happen due to a bug in python2.3. We should be
656 # This can happen due to a bug in python2.3. We should be
657 # able to remove this try/except when 2.4 becomes a
657 # able to remove this try/except when 2.4 becomes a
658 # requirement. Bug details at http://python.org/sf/1005466
658 # requirement. Bug details at http://python.org/sf/1005466
659 inspect_error()
659 inspect_error()
660 traceback.print_exc(file=Term.cerr)
660 traceback.print_exc(file=Term.cerr)
661 info("\nIPython's exception reporting continues...\n")
661 info("\nIPython's exception reporting continues...\n")
662
662
663 if func == '?':
663 if func == '?':
664 call = ''
664 call = ''
665 else:
665 else:
666 # Decide whether to include variable details or not
666 # Decide whether to include variable details or not
667 var_repr = self.include_vars and eqrepr or nullrepr
667 var_repr = self.include_vars and eqrepr or nullrepr
668 try:
668 try:
669 call = tpl_call % (func,inspect.formatargvalues(args,
669 call = tpl_call % (func,inspect.formatargvalues(args,
670 varargs, varkw,
670 varargs, varkw,
671 locals,formatvalue=var_repr))
671 locals,formatvalue=var_repr))
672 except KeyError:
672 except KeyError:
673 # Very odd crash from inspect.formatargvalues(). The
673 # Very odd crash from inspect.formatargvalues(). The
674 # scenario under which it appeared was a call to
674 # scenario under which it appeared was a call to
675 # view(array,scale) in NumTut.view.view(), where scale had
675 # view(array,scale) in NumTut.view.view(), where scale had
676 # been defined as a scalar (it should be a tuple). Somehow
676 # been defined as a scalar (it should be a tuple). Somehow
677 # inspect messes up resolving the argument list of view()
677 # inspect messes up resolving the argument list of view()
678 # and barfs out. At some point I should dig into this one
678 # and barfs out. At some point I should dig into this one
679 # and file a bug report about it.
679 # and file a bug report about it.
680 inspect_error()
680 inspect_error()
681 traceback.print_exc(file=Term.cerr)
681 traceback.print_exc(file=Term.cerr)
682 info("\nIPython's exception reporting continues...\n")
682 info("\nIPython's exception reporting continues...\n")
683 call = tpl_call_fail % func
683 call = tpl_call_fail % func
684
684
685 # Initialize a list of names on the current line, which the
685 # Initialize a list of names on the current line, which the
686 # tokenizer below will populate.
686 # tokenizer below will populate.
687 names = []
687 names = []
688
688
689 def tokeneater(token_type, token, start, end, line):
689 def tokeneater(token_type, token, start, end, line):
690 """Stateful tokeneater which builds dotted names.
690 """Stateful tokeneater which builds dotted names.
691
691
692 The list of names it appends to (from the enclosing scope) can
692 The list of names it appends to (from the enclosing scope) can
693 contain repeated composite names. This is unavoidable, since
693 contain repeated composite names. This is unavoidable, since
694 there is no way to disambguate partial dotted structures until
694 there is no way to disambguate partial dotted structures until
695 the full list is known. The caller is responsible for pruning
695 the full list is known. The caller is responsible for pruning
696 the final list of duplicates before using it."""
696 the final list of duplicates before using it."""
697
697
698 # build composite names
698 # build composite names
699 if token == '.':
699 if token == '.':
700 try:
700 try:
701 names[-1] += '.'
701 names[-1] += '.'
702 # store state so the next token is added for x.y.z names
702 # store state so the next token is added for x.y.z names
703 tokeneater.name_cont = True
703 tokeneater.name_cont = True
704 return
704 return
705 except IndexError:
705 except IndexError:
706 pass
706 pass
707 if token_type == tokenize.NAME and token not in keyword.kwlist:
707 if token_type == tokenize.NAME and token not in keyword.kwlist:
708 if tokeneater.name_cont:
708 if tokeneater.name_cont:
709 # Dotted names
709 # Dotted names
710 names[-1] += token
710 names[-1] += token
711 tokeneater.name_cont = False
711 tokeneater.name_cont = False
712 else:
712 else:
713 # Regular new names. We append everything, the caller
713 # Regular new names. We append everything, the caller
714 # will be responsible for pruning the list later. It's
714 # will be responsible for pruning the list later. It's
715 # very tricky to try to prune as we go, b/c composite
715 # very tricky to try to prune as we go, b/c composite
716 # names can fool us. The pruning at the end is easy
716 # names can fool us. The pruning at the end is easy
717 # to do (or the caller can print a list with repeated
717 # to do (or the caller can print a list with repeated
718 # names if so desired.
718 # names if so desired.
719 names.append(token)
719 names.append(token)
720 elif token_type == tokenize.NEWLINE:
720 elif token_type == tokenize.NEWLINE:
721 raise IndexError
721 raise IndexError
722 # we need to store a bit of state in the tokenizer to build
722 # we need to store a bit of state in the tokenizer to build
723 # dotted names
723 # dotted names
724 tokeneater.name_cont = False
724 tokeneater.name_cont = False
725
725
726 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
726 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
727 line = getline(file, lnum[0])
727 line = getline(file, lnum[0])
728 lnum[0] += 1
728 lnum[0] += 1
729 return line
729 return line
730
730
731 # Build the list of names on this line of code where the exception
731 # Build the list of names on this line of code where the exception
732 # occurred.
732 # occurred.
733 try:
733 try:
734 # This builds the names list in-place by capturing it from the
734 # This builds the names list in-place by capturing it from the
735 # enclosing scope.
735 # enclosing scope.
736 tokenize.tokenize(linereader, tokeneater)
736 tokenize.tokenize(linereader, tokeneater)
737 except IndexError:
737 except IndexError:
738 # signals exit of tokenizer
738 # signals exit of tokenizer
739 pass
739 pass
740 except tokenize.TokenError,msg:
740 except tokenize.TokenError,msg:
741 _m = ("An unexpected error occurred while tokenizing input\n"
741 _m = ("An unexpected error occurred while tokenizing input\n"
742 "The following traceback may be corrupted or invalid\n"
742 "The following traceback may be corrupted or invalid\n"
743 "The error message is: %s\n" % msg)
743 "The error message is: %s\n" % msg)
744 error(_m)
744 error(_m)
745
745
746 # prune names list of duplicates, but keep the right order
746 # prune names list of duplicates, but keep the right order
747 unique_names = uniq_stable(names)
747 unique_names = uniq_stable(names)
748
748
749 # Start loop over vars
749 # Start loop over vars
750 lvals = []
750 lvals = []
751 if self.include_vars:
751 if self.include_vars:
752 for name_full in unique_names:
752 for name_full in unique_names:
753 name_base = name_full.split('.',1)[0]
753 name_base = name_full.split('.',1)[0]
754 if name_base in frame.f_code.co_varnames:
754 if name_base in frame.f_code.co_varnames:
755 if locals.has_key(name_base):
755 if locals.has_key(name_base):
756 try:
756 try:
757 value = repr(eval(name_full,locals))
757 value = repr(eval(name_full,locals))
758 except:
758 except:
759 value = undefined
759 value = undefined
760 else:
760 else:
761 value = undefined
761 value = undefined
762 name = tpl_local_var % name_full
762 name = tpl_local_var % name_full
763 else:
763 else:
764 if frame.f_globals.has_key(name_base):
764 if frame.f_globals.has_key(name_base):
765 try:
765 try:
766 value = repr(eval(name_full,frame.f_globals))
766 value = repr(eval(name_full,frame.f_globals))
767 except:
767 except:
768 value = undefined
768 value = undefined
769 else:
769 else:
770 value = undefined
770 value = undefined
771 name = tpl_global_var % name_full
771 name = tpl_global_var % name_full
772 lvals.append(tpl_name_val % (name,value))
772 lvals.append(tpl_name_val % (name,value))
773 if lvals:
773 if lvals:
774 lvals = '%s%s' % (indent,em_normal.join(lvals))
774 lvals = '%s%s' % (indent,em_normal.join(lvals))
775 else:
775 else:
776 lvals = ''
776 lvals = ''
777
777
778 level = '%s %s\n' % (link,call)
778 level = '%s %s\n' % (link,call)
779
779
780 if index is None:
780 if index is None:
781 frames.append(level)
781 frames.append(level)
782 else:
782 else:
783 frames.append('%s%s' % (level,''.join(
783 frames.append('%s%s' % (level,''.join(
784 _format_traceback_lines(lnum,index,lines,Colors,lvals,
784 _format_traceback_lines(lnum,index,lines,Colors,lvals,
785 col_scheme))))
785 col_scheme))))
786
786
787 # Get (safely) a string form of the exception info
787 # Get (safely) a string form of the exception info
788 try:
788 try:
789 etype_str,evalue_str = map(str,(etype,evalue))
789 etype_str,evalue_str = map(str,(etype,evalue))
790 except:
790 except:
791 # User exception is improperly defined.
791 # User exception is improperly defined.
792 etype,evalue = str,sys.exc_info()[:2]
792 etype,evalue = str,sys.exc_info()[:2]
793 etype_str,evalue_str = map(str,(etype,evalue))
793 etype_str,evalue_str = map(str,(etype,evalue))
794 # ... and format it
794 # ... and format it
795 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
795 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
796 ColorsNormal, evalue_str)]
796 ColorsNormal, evalue_str)]
797 if type(evalue) is types.InstanceType:
797 if type(evalue) is types.InstanceType:
798 try:
798 try:
799 names = [w for w in dir(evalue) if isinstance(w, basestring)]
799 names = [w for w in dir(evalue) if isinstance(w, basestring)]
800 except:
800 except:
801 # Every now and then, an object with funny inernals blows up
801 # Every now and then, an object with funny inernals blows up
802 # when dir() is called on it. We do the best we can to report
802 # when dir() is called on it. We do the best we can to report
803 # the problem and continue
803 # the problem and continue
804 _m = '%sException reporting error (object with broken dir())%s:'
804 _m = '%sException reporting error (object with broken dir())%s:'
805 exception.append(_m % (Colors.excName,ColorsNormal))
805 exception.append(_m % (Colors.excName,ColorsNormal))
806 etype_str,evalue_str = map(str,sys.exc_info()[:2])
806 etype_str,evalue_str = map(str,sys.exc_info()[:2])
807 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
807 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
808 ColorsNormal, evalue_str))
808 ColorsNormal, evalue_str))
809 names = []
809 names = []
810 for name in names:
810 for name in names:
811 value = text_repr(getattr(evalue, name))
811 value = text_repr(getattr(evalue, name))
812 exception.append('\n%s%s = %s' % (indent, name, value))
812 exception.append('\n%s%s = %s' % (indent, name, value))
813
813
814 # vds: >>
814 # vds: >>
815 if records:
815 if records:
816 filepath, lnum = records[-1][1:3]
816 filepath, lnum = records[-1][1:3]
817 #print "file:", str(file), "linenb", str(lnum) # dbg
817 #print "file:", str(file), "linenb", str(lnum) # dbg
818 filepath = os.path.abspath(filepath)
818 filepath = os.path.abspath(filepath)
819 ipinst = ipapi.get()
819 ipinst = ipapi.get()
820 if ipinst is not None:
820 if ipinst is not None:
821 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
821 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
822 # vds: <<
822 # vds: <<
823
823
824 # return all our info assembled as a single string
824 # return all our info assembled as a single string
825 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
825 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
826
826
827 def debugger(self,force=False):
827 def debugger(self,force=False):
828 """Call up the pdb debugger if desired, always clean up the tb
828 """Call up the pdb debugger if desired, always clean up the tb
829 reference.
829 reference.
830
830
831 Keywords:
831 Keywords:
832
832
833 - force(False): by default, this routine checks the instance call_pdb
833 - force(False): by default, this routine checks the instance call_pdb
834 flag and does not actually invoke the debugger if the flag is false.
834 flag and does not actually invoke the debugger if the flag is false.
835 The 'force' option forces the debugger to activate even if the flag
835 The 'force' option forces the debugger to activate even if the flag
836 is false.
836 is false.
837
837
838 If the call_pdb flag is set, the pdb interactive debugger is
838 If the call_pdb flag is set, the pdb interactive debugger is
839 invoked. In all cases, the self.tb reference to the current traceback
839 invoked. In all cases, the self.tb reference to the current traceback
840 is deleted to prevent lingering references which hamper memory
840 is deleted to prevent lingering references which hamper memory
841 management.
841 management.
842
842
843 Note that each call to pdb() does an 'import readline', so if your app
843 Note that each call to pdb() does an 'import readline', so if your app
844 requires a special setup for the readline completers, you'll have to
844 requires a special setup for the readline completers, you'll have to
845 fix that by hand after invoking the exception handler."""
845 fix that by hand after invoking the exception handler."""
846
846
847 if force or self.call_pdb:
847 if force or self.call_pdb:
848 if self.pdb is None:
848 if self.pdb is None:
849 self.pdb = debugger.Pdb(
849 self.pdb = debugger.Pdb(
850 self.color_scheme_table.active_scheme_name)
850 self.color_scheme_table.active_scheme_name)
851 # the system displayhook may have changed, restore the original
851 # the system displayhook may have changed, restore the original
852 # for pdb
852 # for pdb
853 display_trap = DisplayTrap(None, sys.__displayhook__)
853 display_trap = DisplayTrap(None, sys.__displayhook__)
854 with display_trap:
854 with display_trap:
855 self.pdb.reset()
855 self.pdb.reset()
856 # Find the right frame so we don't pop up inside ipython itself
856 # Find the right frame so we don't pop up inside ipython itself
857 if hasattr(self,'tb'):
857 if hasattr(self,'tb') and self.tb is not None:
858 etb = self.tb
858 etb = self.tb
859 else:
859 else:
860 etb = self.tb = sys.last_traceback
860 etb = self.tb = sys.last_traceback
861 while self.tb.tb_next is not None:
861 while self.tb is not None and self.tb.tb_next is not None:
862 self.tb = self.tb.tb_next
862 self.tb = self.tb.tb_next
863 if etb and etb.tb_next:
863 if etb and etb.tb_next:
864 etb = etb.tb_next
864 etb = etb.tb_next
865 self.pdb.botframe = etb.tb_frame
865 self.pdb.botframe = etb.tb_frame
866 self.pdb.interaction(self.tb.tb_frame, self.tb)
866 self.pdb.interaction(self.tb.tb_frame, self.tb)
867
867
868 if hasattr(self,'tb'):
868 if hasattr(self,'tb'):
869 del self.tb
869 del self.tb
870
870
871 def handler(self, info=None):
871 def handler(self, info=None):
872 (etype, evalue, etb) = info or sys.exc_info()
872 (etype, evalue, etb) = info or sys.exc_info()
873 self.tb = etb
873 self.tb = etb
874 Term.cout.flush()
874 Term.cout.flush()
875 print >> Term.cerr, self.text(etype, evalue, etb)
875 print >> Term.cerr, self.text(etype, evalue, etb)
876 Term.cerr.flush()
876 Term.cerr.flush()
877
877
878 # Changed so an instance can just be called as VerboseTB_inst() and print
878 # Changed so an instance can just be called as VerboseTB_inst() and print
879 # out the right info on its own.
879 # out the right info on its own.
880 def __call__(self, etype=None, evalue=None, etb=None):
880 def __call__(self, etype=None, evalue=None, etb=None):
881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
882 if etb is None:
882 if etb is None:
883 self.handler()
883 self.handler()
884 else:
884 else:
885 self.handler((etype, evalue, etb))
885 self.handler((etype, evalue, etb))
886 try:
886 try:
887 self.debugger()
887 self.debugger()
888 except KeyboardInterrupt:
888 except KeyboardInterrupt:
889 print "\nKeyboardInterrupt"
889 print "\nKeyboardInterrupt"
890
890
891 #----------------------------------------------------------------------------
891 #----------------------------------------------------------------------------
892 class FormattedTB(VerboseTB,ListTB):
892 class FormattedTB(VerboseTB,ListTB):
893 """Subclass ListTB but allow calling with a traceback.
893 """Subclass ListTB but allow calling with a traceback.
894
894
895 It can thus be used as a sys.excepthook for Python > 2.1.
895 It can thus be used as a sys.excepthook for Python > 2.1.
896
896
897 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
897 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
898
898
899 Allows a tb_offset to be specified. This is useful for situations where
899 Allows a tb_offset to be specified. This is useful for situations where
900 one needs to remove a number of topmost frames from the traceback (such as
900 one needs to remove a number of topmost frames from the traceback (such as
901 occurs with python programs that themselves execute other python code,
901 occurs with python programs that themselves execute other python code,
902 like Python shells). """
902 like Python shells). """
903
903
904 def __init__(self, mode = 'Plain', color_scheme='Linux',
904 def __init__(self, mode = 'Plain', color_scheme='Linux',
905 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
905 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
906
906
907 # NEVER change the order of this list. Put new modes at the end:
907 # NEVER change the order of this list. Put new modes at the end:
908 self.valid_modes = ['Plain','Context','Verbose']
908 self.valid_modes = ['Plain','Context','Verbose']
909 self.verbose_modes = self.valid_modes[1:3]
909 self.verbose_modes = self.valid_modes[1:3]
910
910
911 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
911 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
912 call_pdb=call_pdb,include_vars=include_vars)
912 call_pdb=call_pdb,include_vars=include_vars)
913 self.set_mode(mode)
913 self.set_mode(mode)
914
914
915 def _extract_tb(self,tb):
915 def _extract_tb(self,tb):
916 if tb:
916 if tb:
917 return traceback.extract_tb(tb)
917 return traceback.extract_tb(tb)
918 else:
918 else:
919 return None
919 return None
920
920
921 def text(self, etype, value, tb,context=5,mode=None):
921 def text(self, etype, value, tb,context=5,mode=None):
922 """Return formatted traceback.
922 """Return formatted traceback.
923
923
924 If the optional mode parameter is given, it overrides the current
924 If the optional mode parameter is given, it overrides the current
925 mode."""
925 mode."""
926
926
927 if mode is None:
927 if mode is None:
928 mode = self.mode
928 mode = self.mode
929 if mode in self.verbose_modes:
929 if mode in self.verbose_modes:
930 # verbose modes need a full traceback
930 # verbose modes need a full traceback
931 return VerboseTB.text(self,etype, value, tb,context=5)
931 return VerboseTB.text(self,etype, value, tb,context=5)
932 else:
932 else:
933 # We must check the source cache because otherwise we can print
933 # We must check the source cache because otherwise we can print
934 # out-of-date source code.
934 # out-of-date source code.
935 linecache.checkcache()
935 linecache.checkcache()
936 # Now we can extract and format the exception
936 # Now we can extract and format the exception
937 elist = self._extract_tb(tb)
937 elist = self._extract_tb(tb)
938 if len(elist) > self.tb_offset:
938 if len(elist) > self.tb_offset:
939 del elist[:self.tb_offset]
939 del elist[:self.tb_offset]
940 return ListTB.text(self,etype,value,elist)
940 return ListTB.text(self,etype,value,elist)
941
941
942 def set_mode(self,mode=None):
942 def set_mode(self,mode=None):
943 """Switch to the desired mode.
943 """Switch to the desired mode.
944
944
945 If mode is not specified, cycles through the available modes."""
945 If mode is not specified, cycles through the available modes."""
946
946
947 if not mode:
947 if not mode:
948 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
948 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
949 len(self.valid_modes)
949 len(self.valid_modes)
950 self.mode = self.valid_modes[new_idx]
950 self.mode = self.valid_modes[new_idx]
951 elif mode not in self.valid_modes:
951 elif mode not in self.valid_modes:
952 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
952 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
953 'Valid modes: '+str(self.valid_modes)
953 'Valid modes: '+str(self.valid_modes)
954 else:
954 else:
955 self.mode = mode
955 self.mode = mode
956 # include variable details only in 'Verbose' mode
956 # include variable details only in 'Verbose' mode
957 self.include_vars = (self.mode == self.valid_modes[2])
957 self.include_vars = (self.mode == self.valid_modes[2])
958
958
959 # some convenient shorcuts
959 # some convenient shorcuts
960 def plain(self):
960 def plain(self):
961 self.set_mode(self.valid_modes[0])
961 self.set_mode(self.valid_modes[0])
962
962
963 def context(self):
963 def context(self):
964 self.set_mode(self.valid_modes[1])
964 self.set_mode(self.valid_modes[1])
965
965
966 def verbose(self):
966 def verbose(self):
967 self.set_mode(self.valid_modes[2])
967 self.set_mode(self.valid_modes[2])
968
968
969 #----------------------------------------------------------------------------
969 #----------------------------------------------------------------------------
970 class AutoFormattedTB(FormattedTB):
970 class AutoFormattedTB(FormattedTB):
971 """A traceback printer which can be called on the fly.
971 """A traceback printer which can be called on the fly.
972
972
973 It will find out about exceptions by itself.
973 It will find out about exceptions by itself.
974
974
975 A brief example:
975 A brief example:
976
976
977 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
977 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
978 try:
978 try:
979 ...
979 ...
980 except:
980 except:
981 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
981 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
982 """
982 """
983 def __call__(self,etype=None,evalue=None,etb=None,
983 def __call__(self,etype=None,evalue=None,etb=None,
984 out=None,tb_offset=None):
984 out=None,tb_offset=None):
985 """Print out a formatted exception traceback.
985 """Print out a formatted exception traceback.
986
986
987 Optional arguments:
987 Optional arguments:
988 - out: an open file-like object to direct output to.
988 - out: an open file-like object to direct output to.
989
989
990 - tb_offset: the number of frames to skip over in the stack, on a
990 - tb_offset: the number of frames to skip over in the stack, on a
991 per-call basis (this overrides temporarily the instance's tb_offset
991 per-call basis (this overrides temporarily the instance's tb_offset
992 given at initialization time. """
992 given at initialization time. """
993
993
994 if out is None:
994 if out is None:
995 out = Term.cerr
995 out = Term.cerr
996 Term.cout.flush()
996 Term.cout.flush()
997 if tb_offset is not None:
997 if tb_offset is not None:
998 tb_offset, self.tb_offset = self.tb_offset, tb_offset
998 tb_offset, self.tb_offset = self.tb_offset, tb_offset
999 print >> out, self.text(etype, evalue, etb)
999 print >> out, self.text(etype, evalue, etb)
1000 self.tb_offset = tb_offset
1000 self.tb_offset = tb_offset
1001 else:
1001 else:
1002 print >> out, self.text(etype, evalue, etb)
1002 print >> out, self.text(etype, evalue, etb)
1003 out.flush()
1003 out.flush()
1004 try:
1004 try:
1005 self.debugger()
1005 self.debugger()
1006 except KeyboardInterrupt:
1006 except KeyboardInterrupt:
1007 print "\nKeyboardInterrupt"
1007 print "\nKeyboardInterrupt"
1008
1008
1009 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1009 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1010 if etype is None:
1010 if etype is None:
1011 etype,value,tb = sys.exc_info()
1011 etype,value,tb = sys.exc_info()
1012 self.tb = tb
1012 self.tb = tb
1013 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1013 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1014
1014
1015 #---------------------------------------------------------------------------
1015 #---------------------------------------------------------------------------
1016 # A simple class to preserve Nathan's original functionality.
1016 # A simple class to preserve Nathan's original functionality.
1017 class ColorTB(FormattedTB):
1017 class ColorTB(FormattedTB):
1018 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1018 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1019 def __init__(self,color_scheme='Linux',call_pdb=0):
1019 def __init__(self,color_scheme='Linux',call_pdb=0):
1020 FormattedTB.__init__(self,color_scheme=color_scheme,
1020 FormattedTB.__init__(self,color_scheme=color_scheme,
1021 call_pdb=call_pdb)
1021 call_pdb=call_pdb)
1022
1022
1023 #----------------------------------------------------------------------------
1023 #----------------------------------------------------------------------------
1024 # module testing (minimal)
1024 # module testing (minimal)
1025 if __name__ == "__main__":
1025 if __name__ == "__main__":
1026 def spam(c, (d, e)):
1026 def spam(c, (d, e)):
1027 x = c + d
1027 x = c + d
1028 y = c * d
1028 y = c * d
1029 foo(x, y)
1029 foo(x, y)
1030
1030
1031 def foo(a, b, bar=1):
1031 def foo(a, b, bar=1):
1032 eggs(a, b + bar)
1032 eggs(a, b + bar)
1033
1033
1034 def eggs(f, g, z=globals()):
1034 def eggs(f, g, z=globals()):
1035 h = f + g
1035 h = f + g
1036 i = f - g
1036 i = f - g
1037 return h / i
1037 return h / i
1038
1038
1039 print ''
1039 print ''
1040 print '*** Before ***'
1040 print '*** Before ***'
1041 try:
1041 try:
1042 print spam(1, (2, 3))
1042 print spam(1, (2, 3))
1043 except:
1043 except:
1044 traceback.print_exc()
1044 traceback.print_exc()
1045 print ''
1045 print ''
1046
1046
1047 handler = ColorTB()
1047 handler = ColorTB()
1048 print '*** ColorTB ***'
1048 print '*** ColorTB ***'
1049 try:
1049 try:
1050 print spam(1, (2, 3))
1050 print spam(1, (2, 3))
1051 except:
1051 except:
1052 apply(handler, sys.exc_info() )
1052 apply(handler, sys.exc_info() )
1053 print ''
1053 print ''
1054
1054
1055 handler = VerboseTB()
1055 handler = VerboseTB()
1056 print '*** VerboseTB ***'
1056 print '*** VerboseTB ***'
1057 try:
1057 try:
1058 print spam(1, (2, 3))
1058 print spam(1, (2, 3))
1059 except:
1059 except:
1060 apply(handler, sys.exc_info() )
1060 apply(handler, sys.exc_info() )
1061 print ''
1061 print ''
1062
1062
General Comments 0
You need to be logged in to leave comments. Login now