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