##// END OF EJS Templates
Fix bug in ultraTB introduced by sync-editor branch.
Fernando Perez -
r1545:ed5b08e7 merge
parent child Browse files
Show More
@@ -1,1059 +1,1061 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 $Id: ultraTB.py 2908 2007-12-30 21:07:46Z vivainio $"""
63 $Id: ultraTB.py 2908 2007-12-30 21:07:46Z vivainio $"""
64
64
65 #*****************************************************************************
65 #*****************************************************************************
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
68 #
68 #
69 # Distributed under the terms of the BSD License. The full license is in
69 # Distributed under the terms of the BSD License. The full license is in
70 # the file COPYING, distributed as part of this software.
70 # the file COPYING, distributed as part of this software.
71 #*****************************************************************************
71 #*****************************************************************************
72
72
73 from IPython import Release
73 from IPython import Release
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
75 Release.authors['Fernando'])
75 Release.authors['Fernando'])
76 __license__ = Release.license
76 __license__ = Release.license
77
77
78 # Required modules
78 # Required modules
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import re
84 import re
85 import string
85 import string
86 import sys
86 import sys
87 import time
87 import time
88 import tokenize
88 import tokenize
89 import traceback
89 import traceback
90 import types
90 import types
91
91
92 # For purposes of monkeypatching inspect to fix a bug in it.
92 # For purposes of monkeypatching inspect to fix a bug in it.
93 from inspect import getsourcefile, getfile, getmodule,\
93 from inspect import getsourcefile, getfile, getmodule,\
94 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
95
95
96
96
97 # IPython's own modules
97 # IPython's own modules
98 # Modified pdb which doesn't damage IPython's readline handling
98 # Modified pdb which doesn't damage IPython's readline handling
99 from IPython import Debugger, PyColorize
99 from IPython import Debugger, PyColorize
100 from IPython.ipstruct import Struct
100 from IPython.ipstruct import Struct
101 from IPython.excolors import ExceptionColors
101 from IPython.excolors import ExceptionColors
102 from IPython.genutils import Term,uniq_stable,error,info
102 from IPython.genutils import Term,uniq_stable,error,info
103
103
104 # Globals
104 # Globals
105 # amount of space to put line numbers before verbose tracebacks
105 # amount of space to put line numbers before verbose tracebacks
106 INDENT_SIZE = 8
106 INDENT_SIZE = 8
107
107
108 # Default color scheme. This is used, for example, by the traceback
108 # Default color scheme. This is used, for example, by the traceback
109 # formatter. When running in an actual IPython instance, the user's rc.colors
109 # formatter. When running in an actual IPython instance, the user's rc.colors
110 # value is used, but havinga module global makes this functionality available
110 # value is used, but havinga module global makes this functionality available
111 # to users of ultraTB who are NOT running inside ipython.
111 # to users of ultraTB who are NOT running inside ipython.
112 DEFAULT_SCHEME = 'NoColor'
112 DEFAULT_SCHEME = 'NoColor'
113
113
114 #---------------------------------------------------------------------------
114 #---------------------------------------------------------------------------
115 # Code begins
115 # Code begins
116
116
117 # Utility functions
117 # Utility functions
118 def inspect_error():
118 def inspect_error():
119 """Print a message about internal inspect errors.
119 """Print a message about internal inspect errors.
120
120
121 These are unfortunately quite common."""
121 These are unfortunately quite common."""
122
122
123 error('Internal Python error in the inspect module.\n'
123 error('Internal Python error in the inspect module.\n'
124 'Below is the traceback from this internal error.\n')
124 'Below is the traceback from this internal error.\n')
125
125
126
126
127 def findsource(object):
127 def findsource(object):
128 """Return the entire source file and starting line number for an object.
128 """Return the entire source file and starting line number for an object.
129
129
130 The argument may be a module, class, method, function, traceback, frame,
130 The argument may be a module, class, method, function, traceback, frame,
131 or code object. The source code is returned as a list of all the lines
131 or code object. The source code is returned as a list of all the lines
132 in the file and the line number indexes a line in that list. An IOError
132 in the file and the line number indexes a line in that list. An IOError
133 is raised if the source code cannot be retrieved.
133 is raised if the source code cannot be retrieved.
134
134
135 FIXED version with which we monkeypatch the stdlib to work around a bug."""
135 FIXED version with which we monkeypatch the stdlib to work around a bug."""
136
136
137 file = getsourcefile(object) or getfile(object)
137 file = getsourcefile(object) or getfile(object)
138 # If the object is a frame, then trying to get the globals dict from its
138 # If the object is a frame, then trying to get the globals dict from its
139 # module won't work. Instead, the frame object itself has the globals
139 # module won't work. Instead, the frame object itself has the globals
140 # dictionary.
140 # dictionary.
141 globals_dict = None
141 globals_dict = None
142 if inspect.isframe(object):
142 if inspect.isframe(object):
143 # XXX: can this ever be false?
143 # XXX: can this ever be false?
144 globals_dict = object.f_globals
144 globals_dict = object.f_globals
145 else:
145 else:
146 module = getmodule(object, file)
146 module = getmodule(object, file)
147 if module:
147 if module:
148 globals_dict = module.__dict__
148 globals_dict = module.__dict__
149 lines = linecache.getlines(file, globals_dict)
149 lines = linecache.getlines(file, globals_dict)
150 if not lines:
150 if not lines:
151 raise IOError('could not get source code')
151 raise IOError('could not get source code')
152
152
153 if ismodule(object):
153 if ismodule(object):
154 return lines, 0
154 return lines, 0
155
155
156 if isclass(object):
156 if isclass(object):
157 name = object.__name__
157 name = object.__name__
158 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
158 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
159 # make some effort to find the best matching class definition:
159 # make some effort to find the best matching class definition:
160 # use the one with the least indentation, which is the one
160 # use the one with the least indentation, which is the one
161 # that's most probably not inside a function definition.
161 # that's most probably not inside a function definition.
162 candidates = []
162 candidates = []
163 for i in range(len(lines)):
163 for i in range(len(lines)):
164 match = pat.match(lines[i])
164 match = pat.match(lines[i])
165 if match:
165 if match:
166 # if it's at toplevel, it's already the best one
166 # if it's at toplevel, it's already the best one
167 if lines[i][0] == 'c':
167 if lines[i][0] == 'c':
168 return lines, i
168 return lines, i
169 # else add whitespace to candidate list
169 # else add whitespace to candidate list
170 candidates.append((match.group(1), i))
170 candidates.append((match.group(1), i))
171 if candidates:
171 if candidates:
172 # this will sort by whitespace, and by line number,
172 # this will sort by whitespace, and by line number,
173 # less whitespace first
173 # less whitespace first
174 candidates.sort()
174 candidates.sort()
175 return lines, candidates[0][1]
175 return lines, candidates[0][1]
176 else:
176 else:
177 raise IOError('could not find class definition')
177 raise IOError('could not find class definition')
178
178
179 if ismethod(object):
179 if ismethod(object):
180 object = object.im_func
180 object = object.im_func
181 if isfunction(object):
181 if isfunction(object):
182 object = object.func_code
182 object = object.func_code
183 if istraceback(object):
183 if istraceback(object):
184 object = object.tb_frame
184 object = object.tb_frame
185 if isframe(object):
185 if isframe(object):
186 object = object.f_code
186 object = object.f_code
187 if iscode(object):
187 if iscode(object):
188 if not hasattr(object, 'co_firstlineno'):
188 if not hasattr(object, 'co_firstlineno'):
189 raise IOError('could not find function definition')
189 raise IOError('could not find function definition')
190 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
190 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
191 pmatch = pat.match
191 pmatch = pat.match
192 # fperez - fix: sometimes, co_firstlineno can give a number larger than
192 # fperez - fix: sometimes, co_firstlineno can give a number larger than
193 # the length of lines, which causes an error. Safeguard against that.
193 # the length of lines, which causes an error. Safeguard against that.
194 lnum = min(object.co_firstlineno,len(lines))-1
194 lnum = min(object.co_firstlineno,len(lines))-1
195 while lnum > 0:
195 while lnum > 0:
196 if pmatch(lines[lnum]): break
196 if pmatch(lines[lnum]): break
197 lnum -= 1
197 lnum -= 1
198
198
199 return lines, lnum
199 return lines, lnum
200 raise IOError('could not find code object')
200 raise IOError('could not find code object')
201
201
202 # Monkeypatch inspect to apply our bugfix. This code only works with py25
202 # Monkeypatch inspect to apply our bugfix. This code only works with py25
203 if sys.version_info[:2] >= (2,5):
203 if sys.version_info[:2] >= (2,5):
204 inspect.findsource = findsource
204 inspect.findsource = findsource
205
205
206 def fix_frame_records_filenames(records):
206 def fix_frame_records_filenames(records):
207 """Try to fix the filenames in each record from inspect.getinnerframes().
207 """Try to fix the filenames in each record from inspect.getinnerframes().
208
208
209 Particularly, modules loaded from within zip files have useless filenames
209 Particularly, modules loaded from within zip files have useless filenames
210 attached to their code object, and inspect.getinnerframes() just uses it.
210 attached to their code object, and inspect.getinnerframes() just uses it.
211 """
211 """
212 fixed_records = []
212 fixed_records = []
213 for frame, filename, line_no, func_name, lines, index in records:
213 for frame, filename, line_no, func_name, lines, index in records:
214 # Look inside the frame's globals dictionary for __file__, which should
214 # Look inside the frame's globals dictionary for __file__, which should
215 # be better.
215 # be better.
216 better_fn = frame.f_globals.get('__file__', None)
216 better_fn = frame.f_globals.get('__file__', None)
217 if isinstance(better_fn, str):
217 if isinstance(better_fn, str):
218 # Check the type just in case someone did something weird with
218 # Check the type just in case someone did something weird with
219 # __file__. It might also be None if the error occurred during
219 # __file__. It might also be None if the error occurred during
220 # import.
220 # import.
221 filename = better_fn
221 filename = better_fn
222 fixed_records.append((frame, filename, line_no, func_name, lines, index))
222 fixed_records.append((frame, filename, line_no, func_name, lines, index))
223 return fixed_records
223 return fixed_records
224
224
225
225
226 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
226 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
227 import linecache
227 import linecache
228 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
228 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
229
229
230 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
230 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
231
231
232 # If the error is at the console, don't build any context, since it would
232 # If the error is at the console, don't build any context, since it would
233 # otherwise produce 5 blank lines printed out (there is no file at the
233 # otherwise produce 5 blank lines printed out (there is no file at the
234 # console)
234 # console)
235 rec_check = records[tb_offset:]
235 rec_check = records[tb_offset:]
236 try:
236 try:
237 rname = rec_check[0][1]
237 rname = rec_check[0][1]
238 if rname == '<ipython console>' or rname.endswith('<string>'):
238 if rname == '<ipython console>' or rname.endswith('<string>'):
239 return rec_check
239 return rec_check
240 except IndexError:
240 except IndexError:
241 pass
241 pass
242
242
243 aux = traceback.extract_tb(etb)
243 aux = traceback.extract_tb(etb)
244 assert len(records) == len(aux)
244 assert len(records) == len(aux)
245 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
245 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
246 maybeStart = lnum-1 - context//2
246 maybeStart = lnum-1 - context//2
247 start = max(maybeStart, 0)
247 start = max(maybeStart, 0)
248 end = start + context
248 end = start + context
249 lines = linecache.getlines(file)[start:end]
249 lines = linecache.getlines(file)[start:end]
250 # pad with empty lines if necessary
250 # pad with empty lines if necessary
251 if maybeStart < 0:
251 if maybeStart < 0:
252 lines = (['\n'] * -maybeStart) + lines
252 lines = (['\n'] * -maybeStart) + lines
253 if len(lines) < context:
253 if len(lines) < context:
254 lines += ['\n'] * (context - len(lines))
254 lines += ['\n'] * (context - len(lines))
255 buf = list(records[i])
255 buf = list(records[i])
256 buf[LNUM_POS] = lnum
256 buf[LNUM_POS] = lnum
257 buf[INDEX_POS] = lnum - 1 - start
257 buf[INDEX_POS] = lnum - 1 - start
258 buf[LINES_POS] = lines
258 buf[LINES_POS] = lines
259 records[i] = tuple(buf)
259 records[i] = tuple(buf)
260 return records[tb_offset:]
260 return records[tb_offset:]
261
261
262 # Helper function -- largely belongs to VerboseTB, but we need the same
262 # Helper function -- largely belongs to VerboseTB, but we need the same
263 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
263 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
264 # can be recognized properly by ipython.el's py-traceback-line-re
264 # can be recognized properly by ipython.el's py-traceback-line-re
265 # (SyntaxErrors have to be treated specially because they have no traceback)
265 # (SyntaxErrors have to be treated specially because they have no traceback)
266
266
267 _parser = PyColorize.Parser()
267 _parser = PyColorize.Parser()
268
268
269 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
269 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
270 numbers_width = INDENT_SIZE - 1
270 numbers_width = INDENT_SIZE - 1
271 res = []
271 res = []
272 i = lnum - index
272 i = lnum - index
273
273
274 # This lets us get fully syntax-highlighted tracebacks.
274 # This lets us get fully syntax-highlighted tracebacks.
275 if scheme is None:
275 if scheme is None:
276 try:
276 try:
277 scheme = __IPYTHON__.rc.colors
277 scheme = __IPYTHON__.rc.colors
278 except:
278 except:
279 scheme = DEFAULT_SCHEME
279 scheme = DEFAULT_SCHEME
280 _line_format = _parser.format2
280 _line_format = _parser.format2
281
281
282 for line in lines:
282 for line in lines:
283 new_line, err = _line_format(line,'str',scheme)
283 new_line, err = _line_format(line,'str',scheme)
284 if not err: line = new_line
284 if not err: line = new_line
285
285
286 if i == lnum:
286 if i == lnum:
287 # This is the line with the error
287 # This is the line with the error
288 pad = numbers_width - len(str(i))
288 pad = numbers_width - len(str(i))
289 if pad >= 3:
289 if pad >= 3:
290 marker = '-'*(pad-3) + '-> '
290 marker = '-'*(pad-3) + '-> '
291 elif pad == 2:
291 elif pad == 2:
292 marker = '> '
292 marker = '> '
293 elif pad == 1:
293 elif pad == 1:
294 marker = '>'
294 marker = '>'
295 else:
295 else:
296 marker = ''
296 marker = ''
297 num = marker + str(i)
297 num = marker + str(i)
298 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
299 Colors.line, line, Colors.Normal)
299 Colors.line, line, Colors.Normal)
300 else:
300 else:
301 num = '%*s' % (numbers_width,i)
301 num = '%*s' % (numbers_width,i)
302 line = '%s%s%s %s' %(Colors.lineno, num,
302 line = '%s%s%s %s' %(Colors.lineno, num,
303 Colors.Normal, line)
303 Colors.Normal, line)
304
304
305 res.append(line)
305 res.append(line)
306 if lvals and i == lnum:
306 if lvals and i == lnum:
307 res.append(lvals + '\n')
307 res.append(lvals + '\n')
308 i = i + 1
308 i = i + 1
309 return res
309 return res
310
310
311
311
312 #---------------------------------------------------------------------------
312 #---------------------------------------------------------------------------
313 # Module classes
313 # Module classes
314 class TBTools:
314 class TBTools:
315 """Basic tools used by all traceback printer classes."""
315 """Basic tools used by all traceback printer classes."""
316
316
317 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
317 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
318 # Whether to call the interactive pdb debugger after printing
318 # Whether to call the interactive pdb debugger after printing
319 # tracebacks or not
319 # tracebacks or not
320 self.call_pdb = call_pdb
320 self.call_pdb = call_pdb
321
321
322 # Create color table
322 # Create color table
323 self.color_scheme_table = ExceptionColors
323 self.color_scheme_table = ExceptionColors
324
324
325 self.set_colors(color_scheme)
325 self.set_colors(color_scheme)
326 self.old_scheme = color_scheme # save initial value for toggles
326 self.old_scheme = color_scheme # save initial value for toggles
327
327
328 if call_pdb:
328 if call_pdb:
329 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
329 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
330 else:
330 else:
331 self.pdb = None
331 self.pdb = None
332
332
333 def set_colors(self,*args,**kw):
333 def set_colors(self,*args,**kw):
334 """Shorthand access to the color table scheme selector method."""
334 """Shorthand access to the color table scheme selector method."""
335
335
336 # Set own color table
336 # Set own color table
337 self.color_scheme_table.set_active_scheme(*args,**kw)
337 self.color_scheme_table.set_active_scheme(*args,**kw)
338 # for convenience, set Colors to the active scheme
338 # for convenience, set Colors to the active scheme
339 self.Colors = self.color_scheme_table.active_colors
339 self.Colors = self.color_scheme_table.active_colors
340 # Also set colors of debugger
340 # Also set colors of debugger
341 if hasattr(self,'pdb') and self.pdb is not None:
341 if hasattr(self,'pdb') and self.pdb is not None:
342 self.pdb.set_colors(*args,**kw)
342 self.pdb.set_colors(*args,**kw)
343
343
344 def color_toggle(self):
344 def color_toggle(self):
345 """Toggle between the currently active color scheme and NoColor."""
345 """Toggle between the currently active color scheme and NoColor."""
346
346
347 if self.color_scheme_table.active_scheme_name == 'NoColor':
347 if self.color_scheme_table.active_scheme_name == 'NoColor':
348 self.color_scheme_table.set_active_scheme(self.old_scheme)
348 self.color_scheme_table.set_active_scheme(self.old_scheme)
349 self.Colors = self.color_scheme_table.active_colors
349 self.Colors = self.color_scheme_table.active_colors
350 else:
350 else:
351 self.old_scheme = self.color_scheme_table.active_scheme_name
351 self.old_scheme = self.color_scheme_table.active_scheme_name
352 self.color_scheme_table.set_active_scheme('NoColor')
352 self.color_scheme_table.set_active_scheme('NoColor')
353 self.Colors = self.color_scheme_table.active_colors
353 self.Colors = self.color_scheme_table.active_colors
354
354
355 #---------------------------------------------------------------------------
355 #---------------------------------------------------------------------------
356 class ListTB(TBTools):
356 class ListTB(TBTools):
357 """Print traceback information from a traceback list, with optional color.
357 """Print traceback information from a traceback list, with optional color.
358
358
359 Calling: requires 3 arguments:
359 Calling: requires 3 arguments:
360 (etype, evalue, elist)
360 (etype, evalue, elist)
361 as would be obtained by:
361 as would be obtained by:
362 etype, evalue, tb = sys.exc_info()
362 etype, evalue, tb = sys.exc_info()
363 if tb:
363 if tb:
364 elist = traceback.extract_tb(tb)
364 elist = traceback.extract_tb(tb)
365 else:
365 else:
366 elist = None
366 elist = None
367
367
368 It can thus be used by programs which need to process the traceback before
368 It can thus be used by programs which need to process the traceback before
369 printing (such as console replacements based on the code module from the
369 printing (such as console replacements based on the code module from the
370 standard library).
370 standard library).
371
371
372 Because they are meant to be called without a full traceback (only a
372 Because they are meant to be called without a full traceback (only a
373 list), instances of this class can't call the interactive pdb debugger."""
373 list), instances of this class can't call the interactive pdb debugger."""
374
374
375 def __init__(self,color_scheme = 'NoColor'):
375 def __init__(self,color_scheme = 'NoColor'):
376 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
376 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
377
377
378 def __call__(self, etype, value, elist):
378 def __call__(self, etype, value, elist):
379 Term.cout.flush()
379 Term.cout.flush()
380 print >> Term.cerr, self.text(etype,value,elist)
380 print >> Term.cerr, self.text(etype,value,elist)
381 Term.cerr.flush()
381 Term.cerr.flush()
382
382
383 def text(self,etype, value, elist,context=5):
383 def text(self,etype, value, elist,context=5):
384 """Return a color formatted string with the traceback info."""
384 """Return a color formatted string with the traceback info."""
385
385
386 Colors = self.Colors
386 Colors = self.Colors
387 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
387 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
388 if elist:
388 if elist:
389 out_string.append('Traceback %s(most recent call last)%s:' % \
389 out_string.append('Traceback %s(most recent call last)%s:' % \
390 (Colors.normalEm, Colors.Normal) + '\n')
390 (Colors.normalEm, Colors.Normal) + '\n')
391 out_string.extend(self._format_list(elist))
391 out_string.extend(self._format_list(elist))
392 lines = self._format_exception_only(etype, value)
392 lines = self._format_exception_only(etype, value)
393 for line in lines[:-1]:
393 for line in lines[:-1]:
394 out_string.append(" "+line)
394 out_string.append(" "+line)
395 out_string.append(lines[-1])
395 out_string.append(lines[-1])
396 return ''.join(out_string)
396 return ''.join(out_string)
397
397
398 def _format_list(self, extracted_list):
398 def _format_list(self, extracted_list):
399 """Format a list of traceback entry tuples for printing.
399 """Format a list of traceback entry tuples for printing.
400
400
401 Given a list of tuples as returned by extract_tb() or
401 Given a list of tuples as returned by extract_tb() or
402 extract_stack(), return a list of strings ready for printing.
402 extract_stack(), return a list of strings ready for printing.
403 Each string in the resulting list corresponds to the item with the
403 Each string in the resulting list corresponds to the item with the
404 same index in the argument list. Each string ends in a newline;
404 same index in the argument list. Each string ends in a newline;
405 the strings may contain internal newlines as well, for those items
405 the strings may contain internal newlines as well, for those items
406 whose source text line is not None.
406 whose source text line is not None.
407
407
408 Lifted almost verbatim from traceback.py
408 Lifted almost verbatim from traceback.py
409 """
409 """
410
410
411 Colors = self.Colors
411 Colors = self.Colors
412 list = []
412 list = []
413 for filename, lineno, name, line in extracted_list[:-1]:
413 for filename, lineno, name, line in extracted_list[:-1]:
414 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
414 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
415 (Colors.filename, filename, Colors.Normal,
415 (Colors.filename, filename, Colors.Normal,
416 Colors.lineno, lineno, Colors.Normal,
416 Colors.lineno, lineno, Colors.Normal,
417 Colors.name, name, Colors.Normal)
417 Colors.name, name, Colors.Normal)
418 if line:
418 if line:
419 item = item + ' %s\n' % line.strip()
419 item = item + ' %s\n' % line.strip()
420 list.append(item)
420 list.append(item)
421 # Emphasize the last entry
421 # Emphasize the last entry
422 filename, lineno, name, line = extracted_list[-1]
422 filename, lineno, name, line = extracted_list[-1]
423 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
423 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
424 (Colors.normalEm,
424 (Colors.normalEm,
425 Colors.filenameEm, filename, Colors.normalEm,
425 Colors.filenameEm, filename, Colors.normalEm,
426 Colors.linenoEm, lineno, Colors.normalEm,
426 Colors.linenoEm, lineno, Colors.normalEm,
427 Colors.nameEm, name, Colors.normalEm,
427 Colors.nameEm, name, Colors.normalEm,
428 Colors.Normal)
428 Colors.Normal)
429 if line:
429 if line:
430 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
430 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
431 Colors.Normal)
431 Colors.Normal)
432 list.append(item)
432 list.append(item)
433 return list
433 return list
434
434
435 def _format_exception_only(self, etype, value):
435 def _format_exception_only(self, etype, value):
436 """Format the exception part of a traceback.
436 """Format the exception part of a traceback.
437
437
438 The arguments are the exception type and value such as given by
438 The arguments are the exception type and value such as given by
439 sys.exc_info()[:2]. The return value is a list of strings, each ending
439 sys.exc_info()[:2]. The return value is a list of strings, each ending
440 in a newline. Normally, the list contains a single string; however,
440 in a newline. Normally, the list contains a single string; however,
441 for SyntaxError exceptions, it contains several lines that (when
441 for SyntaxError exceptions, it contains several lines that (when
442 printed) display detailed information about where the syntax error
442 printed) display detailed information about where the syntax error
443 occurred. The message indicating which exception occurred is the
443 occurred. The message indicating which exception occurred is the
444 always last string in the list.
444 always last string in the list.
445
445
446 Also lifted nearly verbatim from traceback.py
446 Also lifted nearly verbatim from traceback.py
447 """
447 """
448
448
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 pass
462 have_filedata = False
463 else:
463 else:
464 have_filedata = True
464 #print 'filename is',filename # dbg
465 #print 'filename is',filename # dbg
465 if not filename: filename = "<string>"
466 if not filename: filename = "<string>"
466 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' % \
467 (Colors.normalEm,
468 (Colors.normalEm,
468 Colors.filenameEm, filename, Colors.normalEm,
469 Colors.filenameEm, filename, Colors.normalEm,
469 Colors.linenoEm, lineno, Colors.Normal ))
470 Colors.linenoEm, lineno, Colors.Normal ))
470 if line is not None:
471 if line is not None:
471 i = 0
472 i = 0
472 while i < len(line) and line[i].isspace():
473 while i < len(line) and line[i].isspace():
473 i = i+1
474 i = i+1
474 list.append('%s %s%s\n' % (Colors.line,
475 list.append('%s %s%s\n' % (Colors.line,
475 line.strip(),
476 line.strip(),
476 Colors.Normal))
477 Colors.Normal))
477 if offset is not None:
478 if offset is not None:
478 s = ' '
479 s = ' '
479 for c in line[i:offset-1]:
480 for c in line[i:offset-1]:
480 if c.isspace():
481 if c.isspace():
481 s = s + c
482 s = s + c
482 else:
483 else:
483 s = s + ' '
484 s = s + ' '
484 list.append('%s%s^%s\n' % (Colors.caret, s,
485 list.append('%s%s^%s\n' % (Colors.caret, s,
485 Colors.Normal) )
486 Colors.Normal) )
486 value = msg
487 value = msg
487 s = self._some_str(value)
488 s = self._some_str(value)
488 if s:
489 if s:
489 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
490 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
490 Colors.Normal, s))
491 Colors.Normal, s))
491 else:
492 else:
492 list.append('%s\n' % str(stype))
493 list.append('%s\n' % str(stype))
493
494
494 # vds:>>
495 # vds:>>
495 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
496 if have_filedata:
497 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
496 # vds:<<
498 # vds:<<
497
499
498 return list
500 return list
499
501
500 def _some_str(self, value):
502 def _some_str(self, value):
501 # Lifted from traceback.py
503 # Lifted from traceback.py
502 try:
504 try:
503 return str(value)
505 return str(value)
504 except:
506 except:
505 return '<unprintable %s object>' % type(value).__name__
507 return '<unprintable %s object>' % type(value).__name__
506
508
507 #----------------------------------------------------------------------------
509 #----------------------------------------------------------------------------
508 class VerboseTB(TBTools):
510 class VerboseTB(TBTools):
509 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
511 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
510 of HTML. Requires inspect and pydoc. Crazy, man.
512 of HTML. Requires inspect and pydoc. Crazy, man.
511
513
512 Modified version which optionally strips the topmost entries from the
514 Modified version which optionally strips the topmost entries from the
513 traceback, to be used with alternate interpreters (because their own code
515 traceback, to be used with alternate interpreters (because their own code
514 would appear in the traceback)."""
516 would appear in the traceback)."""
515
517
516 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
518 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
517 call_pdb = 0, include_vars=1):
519 call_pdb = 0, include_vars=1):
518 """Specify traceback offset, headers and color scheme.
520 """Specify traceback offset, headers and color scheme.
519
521
520 Define how many frames to drop from the tracebacks. Calling it with
522 Define how many frames to drop from the tracebacks. Calling it with
521 tb_offset=1 allows use of this handler in interpreters which will have
523 tb_offset=1 allows use of this handler in interpreters which will have
522 their own code at the top of the traceback (VerboseTB will first
524 their own code at the top of the traceback (VerboseTB will first
523 remove that frame before printing the traceback info)."""
525 remove that frame before printing the traceback info)."""
524 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
526 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
525 self.tb_offset = tb_offset
527 self.tb_offset = tb_offset
526 self.long_header = long_header
528 self.long_header = long_header
527 self.include_vars = include_vars
529 self.include_vars = include_vars
528
530
529 def text(self, etype, evalue, etb, context=5):
531 def text(self, etype, evalue, etb, context=5):
530 """Return a nice text document describing the traceback."""
532 """Return a nice text document describing the traceback."""
531
533
532 # some locals
534 # some locals
533 try:
535 try:
534 etype = etype.__name__
536 etype = etype.__name__
535 except AttributeError:
537 except AttributeError:
536 pass
538 pass
537 Colors = self.Colors # just a shorthand + quicker name lookup
539 Colors = self.Colors # just a shorthand + quicker name lookup
538 ColorsNormal = Colors.Normal # used a lot
540 ColorsNormal = Colors.Normal # used a lot
539 col_scheme = self.color_scheme_table.active_scheme_name
541 col_scheme = self.color_scheme_table.active_scheme_name
540 indent = ' '*INDENT_SIZE
542 indent = ' '*INDENT_SIZE
541 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
543 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
542 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
544 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
543 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
545 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
544
546
545 # some internal-use functions
547 # some internal-use functions
546 def text_repr(value):
548 def text_repr(value):
547 """Hopefully pretty robust repr equivalent."""
549 """Hopefully pretty robust repr equivalent."""
548 # this is pretty horrible but should always return *something*
550 # this is pretty horrible but should always return *something*
549 try:
551 try:
550 return pydoc.text.repr(value)
552 return pydoc.text.repr(value)
551 except KeyboardInterrupt:
553 except KeyboardInterrupt:
552 raise
554 raise
553 except:
555 except:
554 try:
556 try:
555 return repr(value)
557 return repr(value)
556 except KeyboardInterrupt:
558 except KeyboardInterrupt:
557 raise
559 raise
558 except:
560 except:
559 try:
561 try:
560 # all still in an except block so we catch
562 # all still in an except block so we catch
561 # getattr raising
563 # getattr raising
562 name = getattr(value, '__name__', None)
564 name = getattr(value, '__name__', None)
563 if name:
565 if name:
564 # ick, recursion
566 # ick, recursion
565 return text_repr(name)
567 return text_repr(name)
566 klass = getattr(value, '__class__', None)
568 klass = getattr(value, '__class__', None)
567 if klass:
569 if klass:
568 return '%s instance' % text_repr(klass)
570 return '%s instance' % text_repr(klass)
569 except KeyboardInterrupt:
571 except KeyboardInterrupt:
570 raise
572 raise
571 except:
573 except:
572 return 'UNRECOVERABLE REPR FAILURE'
574 return 'UNRECOVERABLE REPR FAILURE'
573 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
575 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
574 def nullrepr(value, repr=text_repr): return ''
576 def nullrepr(value, repr=text_repr): return ''
575
577
576 # meat of the code begins
578 # meat of the code begins
577 try:
579 try:
578 etype = etype.__name__
580 etype = etype.__name__
579 except AttributeError:
581 except AttributeError:
580 pass
582 pass
581
583
582 if self.long_header:
584 if self.long_header:
583 # Header with the exception type, python version, and date
585 # Header with the exception type, python version, and date
584 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
586 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
585 date = time.ctime(time.time())
587 date = time.ctime(time.time())
586
588
587 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
589 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
588 exc, ' '*(75-len(str(etype))-len(pyver)),
590 exc, ' '*(75-len(str(etype))-len(pyver)),
589 pyver, string.rjust(date, 75) )
591 pyver, string.rjust(date, 75) )
590 head += "\nA problem occured executing Python code. Here is the sequence of function"\
592 head += "\nA problem occured executing Python code. Here is the sequence of function"\
591 "\ncalls leading up to the error, with the most recent (innermost) call last."
593 "\ncalls leading up to the error, with the most recent (innermost) call last."
592 else:
594 else:
593 # Simplified header
595 # Simplified header
594 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
596 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
595 string.rjust('Traceback (most recent call last)',
597 string.rjust('Traceback (most recent call last)',
596 75 - len(str(etype)) ) )
598 75 - len(str(etype)) ) )
597 frames = []
599 frames = []
598 # Flush cache before calling inspect. This helps alleviate some of the
600 # Flush cache before calling inspect. This helps alleviate some of the
599 # problems with python 2.3's inspect.py.
601 # problems with python 2.3's inspect.py.
600 linecache.checkcache()
602 linecache.checkcache()
601 # Drop topmost frames if requested
603 # Drop topmost frames if requested
602 try:
604 try:
603 # Try the default getinnerframes and Alex's: Alex's fixes some
605 # Try the default getinnerframes and Alex's: Alex's fixes some
604 # problems, but it generates empty tracebacks for console errors
606 # problems, but it generates empty tracebacks for console errors
605 # (5 blanks lines) where none should be returned.
607 # (5 blanks lines) where none should be returned.
606 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
608 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
607 #print 'python records:', records # dbg
609 #print 'python records:', records # dbg
608 records = _fixed_getinnerframes(etb, context,self.tb_offset)
610 records = _fixed_getinnerframes(etb, context,self.tb_offset)
609 #print 'alex records:', records # dbg
611 #print 'alex records:', records # dbg
610 except:
612 except:
611
613
612 # FIXME: I've been getting many crash reports from python 2.3
614 # FIXME: I've been getting many crash reports from python 2.3
613 # users, traceable to inspect.py. If I can find a small test-case
615 # users, traceable to inspect.py. If I can find a small test-case
614 # to reproduce this, I should either write a better workaround or
616 # to reproduce this, I should either write a better workaround or
615 # file a bug report against inspect (if that's the real problem).
617 # file a bug report against inspect (if that's the real problem).
616 # So far, I haven't been able to find an isolated example to
618 # So far, I haven't been able to find an isolated example to
617 # reproduce the problem.
619 # reproduce the problem.
618 inspect_error()
620 inspect_error()
619 traceback.print_exc(file=Term.cerr)
621 traceback.print_exc(file=Term.cerr)
620 info('\nUnfortunately, your original traceback can not be constructed.\n')
622 info('\nUnfortunately, your original traceback can not be constructed.\n')
621 return ''
623 return ''
622
624
623 # build some color string templates outside these nested loops
625 # build some color string templates outside these nested loops
624 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
626 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
625 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
627 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
626 ColorsNormal)
628 ColorsNormal)
627 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
629 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
628 (Colors.vName, Colors.valEm, ColorsNormal)
630 (Colors.vName, Colors.valEm, ColorsNormal)
629 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
631 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
630 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
632 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
631 Colors.vName, ColorsNormal)
633 Colors.vName, ColorsNormal)
632 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
634 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
633 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
635 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
634 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
636 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
635 ColorsNormal)
637 ColorsNormal)
636
638
637 # now, loop over all records printing context and info
639 # now, loop over all records printing context and info
638 abspath = os.path.abspath
640 abspath = os.path.abspath
639 for frame, file, lnum, func, lines, index in records:
641 for frame, file, lnum, func, lines, index in records:
640 #print '*** record:',file,lnum,func,lines,index # dbg
642 #print '*** record:',file,lnum,func,lines,index # dbg
641 try:
643 try:
642 file = file and abspath(file) or '?'
644 file = file and abspath(file) or '?'
643 except OSError:
645 except OSError:
644 # if file is '<console>' or something not in the filesystem,
646 # if file is '<console>' or something not in the filesystem,
645 # the abspath call will throw an OSError. Just ignore it and
647 # the abspath call will throw an OSError. Just ignore it and
646 # keep the original file string.
648 # keep the original file string.
647 pass
649 pass
648 link = tpl_link % file
650 link = tpl_link % file
649 try:
651 try:
650 args, varargs, varkw, locals = inspect.getargvalues(frame)
652 args, varargs, varkw, locals = inspect.getargvalues(frame)
651 except:
653 except:
652 # This can happen due to a bug in python2.3. We should be
654 # This can happen due to a bug in python2.3. We should be
653 # able to remove this try/except when 2.4 becomes a
655 # able to remove this try/except when 2.4 becomes a
654 # requirement. Bug details at http://python.org/sf/1005466
656 # requirement. Bug details at http://python.org/sf/1005466
655 inspect_error()
657 inspect_error()
656 traceback.print_exc(file=Term.cerr)
658 traceback.print_exc(file=Term.cerr)
657 info("\nIPython's exception reporting continues...\n")
659 info("\nIPython's exception reporting continues...\n")
658
660
659 if func == '?':
661 if func == '?':
660 call = ''
662 call = ''
661 else:
663 else:
662 # Decide whether to include variable details or not
664 # Decide whether to include variable details or not
663 var_repr = self.include_vars and eqrepr or nullrepr
665 var_repr = self.include_vars and eqrepr or nullrepr
664 try:
666 try:
665 call = tpl_call % (func,inspect.formatargvalues(args,
667 call = tpl_call % (func,inspect.formatargvalues(args,
666 varargs, varkw,
668 varargs, varkw,
667 locals,formatvalue=var_repr))
669 locals,formatvalue=var_repr))
668 except KeyError:
670 except KeyError:
669 # Very odd crash from inspect.formatargvalues(). The
671 # Very odd crash from inspect.formatargvalues(). The
670 # scenario under which it appeared was a call to
672 # scenario under which it appeared was a call to
671 # view(array,scale) in NumTut.view.view(), where scale had
673 # view(array,scale) in NumTut.view.view(), where scale had
672 # been defined as a scalar (it should be a tuple). Somehow
674 # been defined as a scalar (it should be a tuple). Somehow
673 # inspect messes up resolving the argument list of view()
675 # inspect messes up resolving the argument list of view()
674 # and barfs out. At some point I should dig into this one
676 # and barfs out. At some point I should dig into this one
675 # and file a bug report about it.
677 # and file a bug report about it.
676 inspect_error()
678 inspect_error()
677 traceback.print_exc(file=Term.cerr)
679 traceback.print_exc(file=Term.cerr)
678 info("\nIPython's exception reporting continues...\n")
680 info("\nIPython's exception reporting continues...\n")
679 call = tpl_call_fail % func
681 call = tpl_call_fail % func
680
682
681 # Initialize a list of names on the current line, which the
683 # Initialize a list of names on the current line, which the
682 # tokenizer below will populate.
684 # tokenizer below will populate.
683 names = []
685 names = []
684
686
685 def tokeneater(token_type, token, start, end, line):
687 def tokeneater(token_type, token, start, end, line):
686 """Stateful tokeneater which builds dotted names.
688 """Stateful tokeneater which builds dotted names.
687
689
688 The list of names it appends to (from the enclosing scope) can
690 The list of names it appends to (from the enclosing scope) can
689 contain repeated composite names. This is unavoidable, since
691 contain repeated composite names. This is unavoidable, since
690 there is no way to disambguate partial dotted structures until
692 there is no way to disambguate partial dotted structures until
691 the full list is known. The caller is responsible for pruning
693 the full list is known. The caller is responsible for pruning
692 the final list of duplicates before using it."""
694 the final list of duplicates before using it."""
693
695
694 # build composite names
696 # build composite names
695 if token == '.':
697 if token == '.':
696 try:
698 try:
697 names[-1] += '.'
699 names[-1] += '.'
698 # store state so the next token is added for x.y.z names
700 # store state so the next token is added for x.y.z names
699 tokeneater.name_cont = True
701 tokeneater.name_cont = True
700 return
702 return
701 except IndexError:
703 except IndexError:
702 pass
704 pass
703 if token_type == tokenize.NAME and token not in keyword.kwlist:
705 if token_type == tokenize.NAME and token not in keyword.kwlist:
704 if tokeneater.name_cont:
706 if tokeneater.name_cont:
705 # Dotted names
707 # Dotted names
706 names[-1] += token
708 names[-1] += token
707 tokeneater.name_cont = False
709 tokeneater.name_cont = False
708 else:
710 else:
709 # Regular new names. We append everything, the caller
711 # Regular new names. We append everything, the caller
710 # will be responsible for pruning the list later. It's
712 # will be responsible for pruning the list later. It's
711 # very tricky to try to prune as we go, b/c composite
713 # very tricky to try to prune as we go, b/c composite
712 # names can fool us. The pruning at the end is easy
714 # names can fool us. The pruning at the end is easy
713 # to do (or the caller can print a list with repeated
715 # to do (or the caller can print a list with repeated
714 # names if so desired.
716 # names if so desired.
715 names.append(token)
717 names.append(token)
716 elif token_type == tokenize.NEWLINE:
718 elif token_type == tokenize.NEWLINE:
717 raise IndexError
719 raise IndexError
718 # we need to store a bit of state in the tokenizer to build
720 # we need to store a bit of state in the tokenizer to build
719 # dotted names
721 # dotted names
720 tokeneater.name_cont = False
722 tokeneater.name_cont = False
721
723
722 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
724 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
723 line = getline(file, lnum[0])
725 line = getline(file, lnum[0])
724 lnum[0] += 1
726 lnum[0] += 1
725 return line
727 return line
726
728
727 # Build the list of names on this line of code where the exception
729 # Build the list of names on this line of code where the exception
728 # occurred.
730 # occurred.
729 try:
731 try:
730 # This builds the names list in-place by capturing it from the
732 # This builds the names list in-place by capturing it from the
731 # enclosing scope.
733 # enclosing scope.
732 tokenize.tokenize(linereader, tokeneater)
734 tokenize.tokenize(linereader, tokeneater)
733 except IndexError:
735 except IndexError:
734 # signals exit of tokenizer
736 # signals exit of tokenizer
735 pass
737 pass
736 except tokenize.TokenError,msg:
738 except tokenize.TokenError,msg:
737 _m = ("An unexpected error occurred while tokenizing input\n"
739 _m = ("An unexpected error occurred while tokenizing input\n"
738 "The following traceback may be corrupted or invalid\n"
740 "The following traceback may be corrupted or invalid\n"
739 "The error message is: %s\n" % msg)
741 "The error message is: %s\n" % msg)
740 error(_m)
742 error(_m)
741
743
742 # prune names list of duplicates, but keep the right order
744 # prune names list of duplicates, but keep the right order
743 unique_names = uniq_stable(names)
745 unique_names = uniq_stable(names)
744
746
745 # Start loop over vars
747 # Start loop over vars
746 lvals = []
748 lvals = []
747 if self.include_vars:
749 if self.include_vars:
748 for name_full in unique_names:
750 for name_full in unique_names:
749 name_base = name_full.split('.',1)[0]
751 name_base = name_full.split('.',1)[0]
750 if name_base in frame.f_code.co_varnames:
752 if name_base in frame.f_code.co_varnames:
751 if locals.has_key(name_base):
753 if locals.has_key(name_base):
752 try:
754 try:
753 value = repr(eval(name_full,locals))
755 value = repr(eval(name_full,locals))
754 except:
756 except:
755 value = undefined
757 value = undefined
756 else:
758 else:
757 value = undefined
759 value = undefined
758 name = tpl_local_var % name_full
760 name = tpl_local_var % name_full
759 else:
761 else:
760 if frame.f_globals.has_key(name_base):
762 if frame.f_globals.has_key(name_base):
761 try:
763 try:
762 value = repr(eval(name_full,frame.f_globals))
764 value = repr(eval(name_full,frame.f_globals))
763 except:
765 except:
764 value = undefined
766 value = undefined
765 else:
767 else:
766 value = undefined
768 value = undefined
767 name = tpl_global_var % name_full
769 name = tpl_global_var % name_full
768 lvals.append(tpl_name_val % (name,value))
770 lvals.append(tpl_name_val % (name,value))
769 if lvals:
771 if lvals:
770 lvals = '%s%s' % (indent,em_normal.join(lvals))
772 lvals = '%s%s' % (indent,em_normal.join(lvals))
771 else:
773 else:
772 lvals = ''
774 lvals = ''
773
775
774 level = '%s %s\n' % (link,call)
776 level = '%s %s\n' % (link,call)
775
777
776 if index is None:
778 if index is None:
777 frames.append(level)
779 frames.append(level)
778 else:
780 else:
779 frames.append('%s%s' % (level,''.join(
781 frames.append('%s%s' % (level,''.join(
780 _formatTracebackLines(lnum,index,lines,Colors,lvals,
782 _formatTracebackLines(lnum,index,lines,Colors,lvals,
781 col_scheme))))
783 col_scheme))))
782
784
783 # Get (safely) a string form of the exception info
785 # Get (safely) a string form of the exception info
784 try:
786 try:
785 etype_str,evalue_str = map(str,(etype,evalue))
787 etype_str,evalue_str = map(str,(etype,evalue))
786 except:
788 except:
787 # User exception is improperly defined.
789 # User exception is improperly defined.
788 etype,evalue = str,sys.exc_info()[:2]
790 etype,evalue = str,sys.exc_info()[:2]
789 etype_str,evalue_str = map(str,(etype,evalue))
791 etype_str,evalue_str = map(str,(etype,evalue))
790 # ... and format it
792 # ... and format it
791 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
793 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
792 ColorsNormal, evalue_str)]
794 ColorsNormal, evalue_str)]
793 if type(evalue) is types.InstanceType:
795 if type(evalue) is types.InstanceType:
794 try:
796 try:
795 names = [w for w in dir(evalue) if isinstance(w, basestring)]
797 names = [w for w in dir(evalue) if isinstance(w, basestring)]
796 except:
798 except:
797 # Every now and then, an object with funny inernals blows up
799 # Every now and then, an object with funny inernals blows up
798 # when dir() is called on it. We do the best we can to report
800 # when dir() is called on it. We do the best we can to report
799 # the problem and continue
801 # the problem and continue
800 _m = '%sException reporting error (object with broken dir())%s:'
802 _m = '%sException reporting error (object with broken dir())%s:'
801 exception.append(_m % (Colors.excName,ColorsNormal))
803 exception.append(_m % (Colors.excName,ColorsNormal))
802 etype_str,evalue_str = map(str,sys.exc_info()[:2])
804 etype_str,evalue_str = map(str,sys.exc_info()[:2])
803 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
805 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
804 ColorsNormal, evalue_str))
806 ColorsNormal, evalue_str))
805 names = []
807 names = []
806 for name in names:
808 for name in names:
807 value = text_repr(getattr(evalue, name))
809 value = text_repr(getattr(evalue, name))
808 exception.append('\n%s%s = %s' % (indent, name, value))
810 exception.append('\n%s%s = %s' % (indent, name, value))
809
811
810 # vds: >>
812 # vds: >>
811 if records:
813 if records:
812 frame, file, lnum, func, lines, index = records[-1]
814 filepath, lnum = records[-1][1:3]
813 #print "file:", str(file), "linenb", str(lnum)
815 #print "file:", str(file), "linenb", str(lnum) # dbg
814 file = abspath(file)
816 filepath = os.path.abspath(filepath)
815 __IPYTHON__.hooks.synchronize_with_editor(file, lnum, 0)
817 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
816 # vds: <<
818 # vds: <<
817
819
818 # return all our info assembled as a single string
820 # return all our info assembled as a single string
819 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
821 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
820
822
821 def debugger(self,force=False):
823 def debugger(self,force=False):
822 """Call up the pdb debugger if desired, always clean up the tb
824 """Call up the pdb debugger if desired, always clean up the tb
823 reference.
825 reference.
824
826
825 Keywords:
827 Keywords:
826
828
827 - force(False): by default, this routine checks the instance call_pdb
829 - force(False): by default, this routine checks the instance call_pdb
828 flag and does not actually invoke the debugger if the flag is false.
830 flag and does not actually invoke the debugger if the flag is false.
829 The 'force' option forces the debugger to activate even if the flag
831 The 'force' option forces the debugger to activate even if the flag
830 is false.
832 is false.
831
833
832 If the call_pdb flag is set, the pdb interactive debugger is
834 If the call_pdb flag is set, the pdb interactive debugger is
833 invoked. In all cases, the self.tb reference to the current traceback
835 invoked. In all cases, the self.tb reference to the current traceback
834 is deleted to prevent lingering references which hamper memory
836 is deleted to prevent lingering references which hamper memory
835 management.
837 management.
836
838
837 Note that each call to pdb() does an 'import readline', so if your app
839 Note that each call to pdb() does an 'import readline', so if your app
838 requires a special setup for the readline completers, you'll have to
840 requires a special setup for the readline completers, you'll have to
839 fix that by hand after invoking the exception handler."""
841 fix that by hand after invoking the exception handler."""
840
842
841 if force or self.call_pdb:
843 if force or self.call_pdb:
842 if self.pdb is None:
844 if self.pdb is None:
843 self.pdb = Debugger.Pdb(
845 self.pdb = Debugger.Pdb(
844 self.color_scheme_table.active_scheme_name)
846 self.color_scheme_table.active_scheme_name)
845 # the system displayhook may have changed, restore the original
847 # the system displayhook may have changed, restore the original
846 # for pdb
848 # for pdb
847 dhook = sys.displayhook
849 dhook = sys.displayhook
848 sys.displayhook = sys.__displayhook__
850 sys.displayhook = sys.__displayhook__
849 self.pdb.reset()
851 self.pdb.reset()
850 # Find the right frame so we don't pop up inside ipython itself
852 # Find the right frame so we don't pop up inside ipython itself
851 if hasattr(self,'tb'):
853 if hasattr(self,'tb'):
852 etb = self.tb
854 etb = self.tb
853 else:
855 else:
854 etb = self.tb = sys.last_traceback
856 etb = self.tb = sys.last_traceback
855 while self.tb.tb_next is not None:
857 while self.tb.tb_next is not None:
856 self.tb = self.tb.tb_next
858 self.tb = self.tb.tb_next
857 try:
859 try:
858 if etb and etb.tb_next:
860 if etb and etb.tb_next:
859 etb = etb.tb_next
861 etb = etb.tb_next
860 self.pdb.botframe = etb.tb_frame
862 self.pdb.botframe = etb.tb_frame
861 self.pdb.interaction(self.tb.tb_frame, self.tb)
863 self.pdb.interaction(self.tb.tb_frame, self.tb)
862 finally:
864 finally:
863 sys.displayhook = dhook
865 sys.displayhook = dhook
864
866
865 if hasattr(self,'tb'):
867 if hasattr(self,'tb'):
866 del self.tb
868 del self.tb
867
869
868 def handler(self, info=None):
870 def handler(self, info=None):
869 (etype, evalue, etb) = info or sys.exc_info()
871 (etype, evalue, etb) = info or sys.exc_info()
870 self.tb = etb
872 self.tb = etb
871 Term.cout.flush()
873 Term.cout.flush()
872 print >> Term.cerr, self.text(etype, evalue, etb)
874 print >> Term.cerr, self.text(etype, evalue, etb)
873 Term.cerr.flush()
875 Term.cerr.flush()
874
876
875 # Changed so an instance can just be called as VerboseTB_inst() and print
877 # Changed so an instance can just be called as VerboseTB_inst() and print
876 # out the right info on its own.
878 # out the right info on its own.
877 def __call__(self, etype=None, evalue=None, etb=None):
879 def __call__(self, etype=None, evalue=None, etb=None):
878 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
880 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
879 if etb is None:
881 if etb is None:
880 self.handler()
882 self.handler()
881 else:
883 else:
882 self.handler((etype, evalue, etb))
884 self.handler((etype, evalue, etb))
883 try:
885 try:
884 self.debugger()
886 self.debugger()
885 except KeyboardInterrupt:
887 except KeyboardInterrupt:
886 print "\nKeyboardInterrupt"
888 print "\nKeyboardInterrupt"
887
889
888 #----------------------------------------------------------------------------
890 #----------------------------------------------------------------------------
889 class FormattedTB(VerboseTB,ListTB):
891 class FormattedTB(VerboseTB,ListTB):
890 """Subclass ListTB but allow calling with a traceback.
892 """Subclass ListTB but allow calling with a traceback.
891
893
892 It can thus be used as a sys.excepthook for Python > 2.1.
894 It can thus be used as a sys.excepthook for Python > 2.1.
893
895
894 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
896 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
895
897
896 Allows a tb_offset to be specified. This is useful for situations where
898 Allows a tb_offset to be specified. This is useful for situations where
897 one needs to remove a number of topmost frames from the traceback (such as
899 one needs to remove a number of topmost frames from the traceback (such as
898 occurs with python programs that themselves execute other python code,
900 occurs with python programs that themselves execute other python code,
899 like Python shells). """
901 like Python shells). """
900
902
901 def __init__(self, mode = 'Plain', color_scheme='Linux',
903 def __init__(self, mode = 'Plain', color_scheme='Linux',
902 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
904 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
903
905
904 # NEVER change the order of this list. Put new modes at the end:
906 # NEVER change the order of this list. Put new modes at the end:
905 self.valid_modes = ['Plain','Context','Verbose']
907 self.valid_modes = ['Plain','Context','Verbose']
906 self.verbose_modes = self.valid_modes[1:3]
908 self.verbose_modes = self.valid_modes[1:3]
907
909
908 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
910 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
909 call_pdb=call_pdb,include_vars=include_vars)
911 call_pdb=call_pdb,include_vars=include_vars)
910 self.set_mode(mode)
912 self.set_mode(mode)
911
913
912 def _extract_tb(self,tb):
914 def _extract_tb(self,tb):
913 if tb:
915 if tb:
914 return traceback.extract_tb(tb)
916 return traceback.extract_tb(tb)
915 else:
917 else:
916 return None
918 return None
917
919
918 def text(self, etype, value, tb,context=5,mode=None):
920 def text(self, etype, value, tb,context=5,mode=None):
919 """Return formatted traceback.
921 """Return formatted traceback.
920
922
921 If the optional mode parameter is given, it overrides the current
923 If the optional mode parameter is given, it overrides the current
922 mode."""
924 mode."""
923
925
924 if mode is None:
926 if mode is None:
925 mode = self.mode
927 mode = self.mode
926 if mode in self.verbose_modes:
928 if mode in self.verbose_modes:
927 # verbose modes need a full traceback
929 # verbose modes need a full traceback
928 return VerboseTB.text(self,etype, value, tb,context=5)
930 return VerboseTB.text(self,etype, value, tb,context=5)
929 else:
931 else:
930 # We must check the source cache because otherwise we can print
932 # We must check the source cache because otherwise we can print
931 # out-of-date source code.
933 # out-of-date source code.
932 linecache.checkcache()
934 linecache.checkcache()
933 # Now we can extract and format the exception
935 # Now we can extract and format the exception
934 elist = self._extract_tb(tb)
936 elist = self._extract_tb(tb)
935 if len(elist) > self.tb_offset:
937 if len(elist) > self.tb_offset:
936 del elist[:self.tb_offset]
938 del elist[:self.tb_offset]
937 return ListTB.text(self,etype,value,elist)
939 return ListTB.text(self,etype,value,elist)
938
940
939 def set_mode(self,mode=None):
941 def set_mode(self,mode=None):
940 """Switch to the desired mode.
942 """Switch to the desired mode.
941
943
942 If mode is not specified, cycles through the available modes."""
944 If mode is not specified, cycles through the available modes."""
943
945
944 if not mode:
946 if not mode:
945 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
947 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
946 len(self.valid_modes)
948 len(self.valid_modes)
947 self.mode = self.valid_modes[new_idx]
949 self.mode = self.valid_modes[new_idx]
948 elif mode not in self.valid_modes:
950 elif mode not in self.valid_modes:
949 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
951 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
950 'Valid modes: '+str(self.valid_modes)
952 'Valid modes: '+str(self.valid_modes)
951 else:
953 else:
952 self.mode = mode
954 self.mode = mode
953 # include variable details only in 'Verbose' mode
955 # include variable details only in 'Verbose' mode
954 self.include_vars = (self.mode == self.valid_modes[2])
956 self.include_vars = (self.mode == self.valid_modes[2])
955
957
956 # some convenient shorcuts
958 # some convenient shorcuts
957 def plain(self):
959 def plain(self):
958 self.set_mode(self.valid_modes[0])
960 self.set_mode(self.valid_modes[0])
959
961
960 def context(self):
962 def context(self):
961 self.set_mode(self.valid_modes[1])
963 self.set_mode(self.valid_modes[1])
962
964
963 def verbose(self):
965 def verbose(self):
964 self.set_mode(self.valid_modes[2])
966 self.set_mode(self.valid_modes[2])
965
967
966 #----------------------------------------------------------------------------
968 #----------------------------------------------------------------------------
967 class AutoFormattedTB(FormattedTB):
969 class AutoFormattedTB(FormattedTB):
968 """A traceback printer which can be called on the fly.
970 """A traceback printer which can be called on the fly.
969
971
970 It will find out about exceptions by itself.
972 It will find out about exceptions by itself.
971
973
972 A brief example:
974 A brief example:
973
975
974 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
976 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
975 try:
977 try:
976 ...
978 ...
977 except:
979 except:
978 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
980 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
979 """
981 """
980 def __call__(self,etype=None,evalue=None,etb=None,
982 def __call__(self,etype=None,evalue=None,etb=None,
981 out=None,tb_offset=None):
983 out=None,tb_offset=None):
982 """Print out a formatted exception traceback.
984 """Print out a formatted exception traceback.
983
985
984 Optional arguments:
986 Optional arguments:
985 - out: an open file-like object to direct output to.
987 - out: an open file-like object to direct output to.
986
988
987 - tb_offset: the number of frames to skip over in the stack, on a
989 - tb_offset: the number of frames to skip over in the stack, on a
988 per-call basis (this overrides temporarily the instance's tb_offset
990 per-call basis (this overrides temporarily the instance's tb_offset
989 given at initialization time. """
991 given at initialization time. """
990
992
991 if out is None:
993 if out is None:
992 out = Term.cerr
994 out = Term.cerr
993 Term.cout.flush()
995 Term.cout.flush()
994 if tb_offset is not None:
996 if tb_offset is not None:
995 tb_offset, self.tb_offset = self.tb_offset, tb_offset
997 tb_offset, self.tb_offset = self.tb_offset, tb_offset
996 print >> out, self.text(etype, evalue, etb)
998 print >> out, self.text(etype, evalue, etb)
997 self.tb_offset = tb_offset
999 self.tb_offset = tb_offset
998 else:
1000 else:
999 print >> out, self.text(etype, evalue, etb)
1001 print >> out, self.text(etype, evalue, etb)
1000 out.flush()
1002 out.flush()
1001 try:
1003 try:
1002 self.debugger()
1004 self.debugger()
1003 except KeyboardInterrupt:
1005 except KeyboardInterrupt:
1004 print "\nKeyboardInterrupt"
1006 print "\nKeyboardInterrupt"
1005
1007
1006 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1008 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1007 if etype is None:
1009 if etype is None:
1008 etype,value,tb = sys.exc_info()
1010 etype,value,tb = sys.exc_info()
1009 self.tb = tb
1011 self.tb = tb
1010 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1012 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1011
1013
1012 #---------------------------------------------------------------------------
1014 #---------------------------------------------------------------------------
1013 # A simple class to preserve Nathan's original functionality.
1015 # A simple class to preserve Nathan's original functionality.
1014 class ColorTB(FormattedTB):
1016 class ColorTB(FormattedTB):
1015 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1017 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1016 def __init__(self,color_scheme='Linux',call_pdb=0):
1018 def __init__(self,color_scheme='Linux',call_pdb=0):
1017 FormattedTB.__init__(self,color_scheme=color_scheme,
1019 FormattedTB.__init__(self,color_scheme=color_scheme,
1018 call_pdb=call_pdb)
1020 call_pdb=call_pdb)
1019
1021
1020 #----------------------------------------------------------------------------
1022 #----------------------------------------------------------------------------
1021 # module testing (minimal)
1023 # module testing (minimal)
1022 if __name__ == "__main__":
1024 if __name__ == "__main__":
1023 def spam(c, (d, e)):
1025 def spam(c, (d, e)):
1024 x = c + d
1026 x = c + d
1025 y = c * d
1027 y = c * d
1026 foo(x, y)
1028 foo(x, y)
1027
1029
1028 def foo(a, b, bar=1):
1030 def foo(a, b, bar=1):
1029 eggs(a, b + bar)
1031 eggs(a, b + bar)
1030
1032
1031 def eggs(f, g, z=globals()):
1033 def eggs(f, g, z=globals()):
1032 h = f + g
1034 h = f + g
1033 i = f - g
1035 i = f - g
1034 return h / i
1036 return h / i
1035
1037
1036 print ''
1038 print ''
1037 print '*** Before ***'
1039 print '*** Before ***'
1038 try:
1040 try:
1039 print spam(1, (2, 3))
1041 print spam(1, (2, 3))
1040 except:
1042 except:
1041 traceback.print_exc()
1043 traceback.print_exc()
1042 print ''
1044 print ''
1043
1045
1044 handler = ColorTB()
1046 handler = ColorTB()
1045 print '*** ColorTB ***'
1047 print '*** ColorTB ***'
1046 try:
1048 try:
1047 print spam(1, (2, 3))
1049 print spam(1, (2, 3))
1048 except:
1050 except:
1049 apply(handler, sys.exc_info() )
1051 apply(handler, sys.exc_info() )
1050 print ''
1052 print ''
1051
1053
1052 handler = VerboseTB()
1054 handler = VerboseTB()
1053 print '*** VerboseTB ***'
1055 print '*** VerboseTB ***'
1054 try:
1056 try:
1055 print spam(1, (2, 3))
1057 print spam(1, (2, 3))
1056 except:
1058 except:
1057 apply(handler, sys.exc_info() )
1059 apply(handler, sys.exc_info() )
1058 print ''
1060 print ''
1059
1061
General Comments 0
You need to be logged in to leave comments. Login now