##// END OF EJS Templates
Update exception colors API to PEP8, various small fixes in related files....
Fernando Perez -
Show More
@@ -1,529 +1,528 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 the command line completion of other programs which include this isn't
6 the command line completion of other programs which include this isn't
7 damaged.
7 damaged.
8
8
9 In the future, this class will be expanded with improvements over the standard
9 In the future, this class will be expanded with improvements over the standard
10 pdb.
10 pdb.
11
11
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 changes. Licensing should therefore be under the standard Python terms. For
13 changes. Licensing should therefore be under the standard Python terms. For
14 details on the PSF (Python Software Foundation) standard license, see:
14 details on the PSF (Python Software Foundation) standard license, see:
15
15
16 http://www.python.org/2.2.3/license.html
16 http://www.python.org/2.2.3/license.html
17
17
18 $Id: Debugger.py 2913 2007-12-31 12:42:14Z vivainio $"""
18 $Id: Debugger.py 2913 2007-12-31 12:42:14Z vivainio $"""
19
19
20 #*****************************************************************************
20 #*****************************************************************************
21 #
21 #
22 # This file is licensed under the PSF license.
22 # This file is licensed under the PSF license.
23 #
23 #
24 # Copyright (C) 2001 Python Software Foundation, www.python.org
24 # Copyright (C) 2001 Python Software Foundation, www.python.org
25 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
25 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
26 #
26 #
27 #
27 #
28 #*****************************************************************************
28 #*****************************************************************************
29
29
30 from IPython import Release
30 from IPython import Release
31 __author__ = '%s <%s>' % Release.authors['Fernando']
31 __author__ = '%s <%s>' % Release.authors['Fernando']
32 __license__ = 'Python'
32 __license__ = 'Python'
33
33
34 import bdb
34 import bdb
35 import cmd
35 import cmd
36 import linecache
36 import linecache
37 import os
37 import os
38 import sys
38 import sys
39
39
40 from IPython import PyColorize, ColorANSI, ipapi
40 from IPython import PyColorize, ColorANSI, ipapi
41 from IPython.genutils import Term
41 from IPython.genutils import Term
42 from IPython.excolors import ExceptionColors
42 from IPython.excolors import exception_colors
43
43
44 # See if we can use pydb.
44 # See if we can use pydb.
45 has_pydb = False
45 has_pydb = False
46 prompt = 'ipdb> '
46 prompt = 'ipdb> '
47 #We have to check this directly from sys.argv, config struct not yet available
47 #We have to check this directly from sys.argv, config struct not yet available
48 if '-pydb' in sys.argv:
48 if '-pydb' in sys.argv:
49 try:
49 try:
50 import pydb
50 import pydb
51 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
51 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
52 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
52 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
53 # better protect against it.
53 # better protect against it.
54 has_pydb = True
54 has_pydb = True
55 except ImportError:
55 except ImportError:
56 print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
56 print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
57
57
58 if has_pydb:
58 if has_pydb:
59 from pydb import Pdb as OldPdb
59 from pydb import Pdb as OldPdb
60 #print "Using pydb for %run -d and post-mortem" #dbg
60 #print "Using pydb for %run -d and post-mortem" #dbg
61 prompt = 'ipydb> '
61 prompt = 'ipydb> '
62 else:
62 else:
63 from pdb import Pdb as OldPdb
63 from pdb import Pdb as OldPdb
64
64
65 # Allow the set_trace code to operate outside of an ipython instance, even if
65 # Allow the set_trace code to operate outside of an ipython instance, even if
66 # it does so with some limitations. The rest of this support is implemented in
66 # it does so with some limitations. The rest of this support is implemented in
67 # the Tracer constructor.
67 # the Tracer constructor.
68 def BdbQuit_excepthook(et,ev,tb):
68 def BdbQuit_excepthook(et,ev,tb):
69 if et==bdb.BdbQuit:
69 if et==bdb.BdbQuit:
70 print 'Exiting Debugger.'
70 print 'Exiting Debugger.'
71 else:
71 else:
72 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
72 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
73
73
74 def BdbQuit_IPython_excepthook(self,et,ev,tb):
74 def BdbQuit_IPython_excepthook(self,et,ev,tb):
75 print 'Exiting Debugger.'
75 print 'Exiting Debugger.'
76
76
77 class Tracer(object):
77 class Tracer(object):
78 """Class for local debugging, similar to pdb.set_trace.
78 """Class for local debugging, similar to pdb.set_trace.
79
79
80 Instances of this class, when called, behave like pdb.set_trace, but
80 Instances of this class, when called, behave like pdb.set_trace, but
81 providing IPython's enhanced capabilities.
81 providing IPython's enhanced capabilities.
82
82
83 This is implemented as a class which must be initialized in your own code
83 This is implemented as a class which must be initialized in your own code
84 and not as a standalone function because we need to detect at runtime
84 and not as a standalone function because we need to detect at runtime
85 whether IPython is already active or not. That detection is done in the
85 whether IPython is already active or not. That detection is done in the
86 constructor, ensuring that this code plays nicely with a running IPython,
86 constructor, ensuring that this code plays nicely with a running IPython,
87 while functioning acceptably (though with limitations) if outside of it.
87 while functioning acceptably (though with limitations) if outside of it.
88 """
88 """
89
89
90 def __init__(self,colors=None):
90 def __init__(self,colors=None):
91 """Create a local debugger instance.
91 """Create a local debugger instance.
92
92
93 :Parameters:
93 :Parameters:
94
94
95 - `colors` (None): a string containing the name of the color scheme to
95 - `colors` (None): a string containing the name of the color scheme to
96 use, it must be one of IPython's valid color schemes. If not given, the
96 use, it must be one of IPython's valid color schemes. If not given, the
97 function will default to the current IPython scheme when running inside
97 function will default to the current IPython scheme when running inside
98 IPython, and to 'NoColor' otherwise.
98 IPython, and to 'NoColor' otherwise.
99
99
100 Usage example:
100 Usage example:
101
101
102 from IPython.Debugger import Tracer; debug_here = Tracer()
102 from IPython.Debugger import Tracer; debug_here = Tracer()
103
103
104 ... later in your code
104 ... later in your code
105 debug_here() # -> will open up the debugger at that point.
105 debug_here() # -> will open up the debugger at that point.
106
106
107 Once the debugger activates, you can use all of its regular commands to
107 Once the debugger activates, you can use all of its regular commands to
108 step through code, set breakpoints, etc. See the pdb documentation
108 step through code, set breakpoints, etc. See the pdb documentation
109 from the Python standard library for usage details.
109 from the Python standard library for usage details.
110 """
110 """
111
111
112 global __IPYTHON__
112 global __IPYTHON__
113 try:
113 try:
114 __IPYTHON__
114 __IPYTHON__
115 except NameError:
115 except NameError:
116 # Outside of ipython, we set our own exception hook manually
116 # Outside of ipython, we set our own exception hook manually
117 __IPYTHON__ = ipapi.get(True,False)
117 __IPYTHON__ = ipapi.get(True,False)
118 BdbQuit_excepthook.excepthook_ori = sys.excepthook
118 BdbQuit_excepthook.excepthook_ori = sys.excepthook
119 sys.excepthook = BdbQuit_excepthook
119 sys.excepthook = BdbQuit_excepthook
120 def_colors = 'NoColor'
120 def_colors = 'NoColor'
121 try:
121 try:
122 # Limited tab completion support
122 # Limited tab completion support
123 import rlcompleter,readline
123 import rlcompleter,readline
124 readline.parse_and_bind('tab: complete')
124 readline.parse_and_bind('tab: complete')
125 except ImportError:
125 except ImportError:
126 pass
126 pass
127 else:
127 else:
128 # In ipython, we use its custom exception handler mechanism
128 # In ipython, we use its custom exception handler mechanism
129 ip = ipapi.get()
129 ip = ipapi.get()
130 def_colors = ip.options.colors
130 def_colors = ip.options.colors
131 ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)
131 ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)
132
132
133 if colors is None:
133 if colors is None:
134 colors = def_colors
134 colors = def_colors
135 self.debugger = Pdb(colors)
135 self.debugger = Pdb(colors)
136
136
137 def __call__(self):
137 def __call__(self):
138 """Starts an interactive debugger at the point where called.
138 """Starts an interactive debugger at the point where called.
139
139
140 This is similar to the pdb.set_trace() function from the std lib, but
140 This is similar to the pdb.set_trace() function from the std lib, but
141 using IPython's enhanced debugger."""
141 using IPython's enhanced debugger."""
142
142
143 self.debugger.set_trace(sys._getframe().f_back)
143 self.debugger.set_trace(sys._getframe().f_back)
144
144
145 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
145 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
146 """Make new_fn have old_fn's doc string. This is particularly useful
146 """Make new_fn have old_fn's doc string. This is particularly useful
147 for the do_... commands that hook into the help system.
147 for the do_... commands that hook into the help system.
148 Adapted from from a comp.lang.python posting
148 Adapted from from a comp.lang.python posting
149 by Duncan Booth."""
149 by Duncan Booth."""
150 def wrapper(*args, **kw):
150 def wrapper(*args, **kw):
151 return new_fn(*args, **kw)
151 return new_fn(*args, **kw)
152 if old_fn.__doc__:
152 if old_fn.__doc__:
153 wrapper.__doc__ = old_fn.__doc__ + additional_text
153 wrapper.__doc__ = old_fn.__doc__ + additional_text
154 return wrapper
154 return wrapper
155
155
156 def _file_lines(fname):
156 def _file_lines(fname):
157 """Return the contents of a named file as a list of lines.
157 """Return the contents of a named file as a list of lines.
158
158
159 This function never raises an IOError exception: if the file can't be
159 This function never raises an IOError exception: if the file can't be
160 read, it simply returns an empty list."""
160 read, it simply returns an empty list."""
161
161
162 try:
162 try:
163 outfile = open(fname)
163 outfile = open(fname)
164 except IOError:
164 except IOError:
165 return []
165 return []
166 else:
166 else:
167 out = outfile.readlines()
167 out = outfile.readlines()
168 outfile.close()
168 outfile.close()
169 return out
169 return out
170
170
171 class Pdb(OldPdb):
171 class Pdb(OldPdb):
172 """Modified Pdb class, does not load readline."""
172 """Modified Pdb class, does not load readline."""
173
173
174 if sys.version[:3] >= '2.5' or has_pydb:
174 if sys.version[:3] >= '2.5' or has_pydb:
175 def __init__(self,color_scheme='NoColor',completekey=None,
175 def __init__(self,color_scheme='NoColor',completekey=None,
176 stdin=None, stdout=None):
176 stdin=None, stdout=None):
177
177
178 # Parent constructor:
178 # Parent constructor:
179 if has_pydb and completekey is None:
179 if has_pydb and completekey is None:
180 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
180 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
181 else:
181 else:
182 OldPdb.__init__(self,completekey,stdin,stdout)
182 OldPdb.__init__(self,completekey,stdin,stdout)
183
183
184 self.prompt = prompt # The default prompt is '(Pdb)'
184 self.prompt = prompt # The default prompt is '(Pdb)'
185
185
186 # IPython changes...
186 # IPython changes...
187 self.is_pydb = has_pydb
187 self.is_pydb = has_pydb
188
188
189 if self.is_pydb:
189 if self.is_pydb:
190
190
191 # iplib.py's ipalias seems to want pdb's checkline
191 # iplib.py's ipalias seems to want pdb's checkline
192 # which located in pydb.fn
192 # which located in pydb.fn
193 import pydb.fns
193 import pydb.fns
194 self.checkline = lambda filename, lineno: \
194 self.checkline = lambda filename, lineno: \
195 pydb.fns.checkline(self, filename, lineno)
195 pydb.fns.checkline(self, filename, lineno)
196
196
197 self.curframe = None
197 self.curframe = None
198 self.do_restart = self.new_do_restart
198 self.do_restart = self.new_do_restart
199
199
200 self.old_all_completions = __IPYTHON__.Completer.all_completions
200 self.old_all_completions = __IPYTHON__.Completer.all_completions
201 __IPYTHON__.Completer.all_completions=self.all_completions
201 __IPYTHON__.Completer.all_completions=self.all_completions
202
202
203 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
203 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
204 OldPdb.do_list)
204 OldPdb.do_list)
205 self.do_l = self.do_list
205 self.do_l = self.do_list
206 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
206 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
207 OldPdb.do_frame)
207 OldPdb.do_frame)
208
208
209 self.aliases = {}
209 self.aliases = {}
210
210
211 # Create color table: we copy the default one from the traceback
211 # Create color table: we copy the default one from the traceback
212 # module and add a few attributes needed for debugging
212 # module and add a few attributes needed for debugging
213 self.color_scheme_table = ExceptionColors.copy()
213 self.color_scheme_table = exception_colors()
214
214
215 # shorthands
215 # shorthands
216 C = ColorANSI.TermColors
216 C = ColorANSI.TermColors
217 cst = self.color_scheme_table
217 cst = self.color_scheme_table
218
218
219 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
219 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
220 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
220 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
221
221
222 cst['Linux'].colors.breakpoint_enabled = C.LightRed
222 cst['Linux'].colors.breakpoint_enabled = C.LightRed
223 cst['Linux'].colors.breakpoint_disabled = C.Red
223 cst['Linux'].colors.breakpoint_disabled = C.Red
224
224
225 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
225 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
226 cst['LightBG'].colors.breakpoint_disabled = C.Red
226 cst['LightBG'].colors.breakpoint_disabled = C.Red
227
227
228 self.set_colors(color_scheme)
228 self.set_colors(color_scheme)
229
229
230 # Add a python parser so we can syntax highlight source while
230 # Add a python parser so we can syntax highlight source while
231 # debugging.
231 # debugging.
232 self.parser = PyColorize.Parser()
232 self.parser = PyColorize.Parser()
233
233
234
234
235 else:
235 else:
236 # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
236 # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
237 # because it binds readline and breaks tab-completion. This means we
237 # because it binds readline and breaks tab-completion. This means we
238 # have to COPY the constructor here.
238 # have to COPY the constructor here.
239 def __init__(self,color_scheme='NoColor'):
239 def __init__(self,color_scheme='NoColor'):
240 bdb.Bdb.__init__(self)
240 bdb.Bdb.__init__(self)
241 cmd.Cmd.__init__(self,completekey=None) # don't load readline
241 cmd.Cmd.__init__(self,completekey=None) # don't load readline
242 self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
242 self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
243 self.aliases = {}
243 self.aliases = {}
244
244
245 # These two lines are part of the py2.4 constructor, let's put them
245 # These two lines are part of the py2.4 constructor, let's put them
246 # unconditionally here as they won't cause any problems in 2.3.
246 # unconditionally here as they won't cause any problems in 2.3.
247 self.mainpyfile = ''
247 self.mainpyfile = ''
248 self._wait_for_mainpyfile = 0
248 self._wait_for_mainpyfile = 0
249
249
250 # Read $HOME/.pdbrc and ./.pdbrc
250 # Read $HOME/.pdbrc and ./.pdbrc
251 try:
251 try:
252 self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
252 self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
253 ".pdbrc"))
253 ".pdbrc"))
254 except KeyError:
254 except KeyError:
255 self.rcLines = []
255 self.rcLines = []
256 self.rcLines.extend(_file_lines(".pdbrc"))
256 self.rcLines.extend(_file_lines(".pdbrc"))
257
257
258 # Create color table: we copy the default one from the traceback
258 # Create color table: we copy the default one from the traceback
259 # module and add a few attributes needed for debugging
259 # module and add a few attributes needed for debugging
260 ExceptionColors.set_active_scheme(color_scheme)
260 self.color_scheme_table = exception_colors()
261 self.color_scheme_table = ExceptionColors.copy()
262
261
263 # shorthands
262 # shorthands
264 C = ColorANSI.TermColors
263 C = ColorANSI.TermColors
265 cst = self.color_scheme_table
264 cst = self.color_scheme_table
266
265
267 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
266 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
268 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
267 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
269
268
270 cst['Linux'].colors.breakpoint_enabled = C.LightRed
269 cst['Linux'].colors.breakpoint_enabled = C.LightRed
271 cst['Linux'].colors.breakpoint_disabled = C.Red
270 cst['Linux'].colors.breakpoint_disabled = C.Red
272
271
273 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
272 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
274 cst['LightBG'].colors.breakpoint_disabled = C.Red
273 cst['LightBG'].colors.breakpoint_disabled = C.Red
275
274
276 self.set_colors(color_scheme)
275 self.set_colors(color_scheme)
277
276
278 # Add a python parser so we can syntax highlight source while
277 # Add a python parser so we can syntax highlight source while
279 # debugging.
278 # debugging.
280 self.parser = PyColorize.Parser()
279 self.parser = PyColorize.Parser()
281
280
282 def set_colors(self, scheme):
281 def set_colors(self, scheme):
283 """Shorthand access to the color table scheme selector method."""
282 """Shorthand access to the color table scheme selector method."""
284 self.color_scheme_table.set_active_scheme(scheme)
283 self.color_scheme_table.set_active_scheme(scheme)
285
284
286 def interaction(self, frame, traceback):
285 def interaction(self, frame, traceback):
287 __IPYTHON__.set_completer_frame(frame)
286 __IPYTHON__.set_completer_frame(frame)
288 OldPdb.interaction(self, frame, traceback)
287 OldPdb.interaction(self, frame, traceback)
289
288
290 def new_do_up(self, arg):
289 def new_do_up(self, arg):
291 OldPdb.do_up(self, arg)
290 OldPdb.do_up(self, arg)
292 __IPYTHON__.set_completer_frame(self.curframe)
291 __IPYTHON__.set_completer_frame(self.curframe)
293 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
292 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
294
293
295 def new_do_down(self, arg):
294 def new_do_down(self, arg):
296 OldPdb.do_down(self, arg)
295 OldPdb.do_down(self, arg)
297 __IPYTHON__.set_completer_frame(self.curframe)
296 __IPYTHON__.set_completer_frame(self.curframe)
298
297
299 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
298 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
300
299
301 def new_do_frame(self, arg):
300 def new_do_frame(self, arg):
302 OldPdb.do_frame(self, arg)
301 OldPdb.do_frame(self, arg)
303 __IPYTHON__.set_completer_frame(self.curframe)
302 __IPYTHON__.set_completer_frame(self.curframe)
304
303
305 def new_do_quit(self, arg):
304 def new_do_quit(self, arg):
306
305
307 if hasattr(self, 'old_all_completions'):
306 if hasattr(self, 'old_all_completions'):
308 __IPYTHON__.Completer.all_completions=self.old_all_completions
307 __IPYTHON__.Completer.all_completions=self.old_all_completions
309
308
310
309
311 return OldPdb.do_quit(self, arg)
310 return OldPdb.do_quit(self, arg)
312
311
313 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
312 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
314
313
315 def new_do_restart(self, arg):
314 def new_do_restart(self, arg):
316 """Restart command. In the context of ipython this is exactly the same
315 """Restart command. In the context of ipython this is exactly the same
317 thing as 'quit'."""
316 thing as 'quit'."""
318 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
317 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
319 return self.do_quit(arg)
318 return self.do_quit(arg)
320
319
321 def postloop(self):
320 def postloop(self):
322 __IPYTHON__.set_completer_frame(None)
321 __IPYTHON__.set_completer_frame(None)
323
322
324 def print_stack_trace(self):
323 def print_stack_trace(self):
325 try:
324 try:
326 for frame_lineno in self.stack:
325 for frame_lineno in self.stack:
327 self.print_stack_entry(frame_lineno, context = 5)
326 self.print_stack_entry(frame_lineno, context = 5)
328 except KeyboardInterrupt:
327 except KeyboardInterrupt:
329 pass
328 pass
330
329
331 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
330 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
332 context = 3):
331 context = 3):
333 #frame, lineno = frame_lineno
332 #frame, lineno = frame_lineno
334 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
333 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
335
334
336 # vds: >>
335 # vds: >>
337 frame, lineno = frame_lineno
336 frame, lineno = frame_lineno
338 filename = frame.f_code.co_filename
337 filename = frame.f_code.co_filename
339 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
338 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
340 # vds: <<
339 # vds: <<
341
340
342 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
341 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
343 import linecache, repr
342 import linecache, repr
344
343
345 ret = []
344 ret = []
346
345
347 Colors = self.color_scheme_table.active_colors
346 Colors = self.color_scheme_table.active_colors
348 ColorsNormal = Colors.Normal
347 ColorsNormal = Colors.Normal
349 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
348 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
350 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
349 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
351 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
350 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
352 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
351 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
353 ColorsNormal)
352 ColorsNormal)
354
353
355 frame, lineno = frame_lineno
354 frame, lineno = frame_lineno
356
355
357 return_value = ''
356 return_value = ''
358 if '__return__' in frame.f_locals:
357 if '__return__' in frame.f_locals:
359 rv = frame.f_locals['__return__']
358 rv = frame.f_locals['__return__']
360 #return_value += '->'
359 #return_value += '->'
361 return_value += repr.repr(rv) + '\n'
360 return_value += repr.repr(rv) + '\n'
362 ret.append(return_value)
361 ret.append(return_value)
363
362
364 #s = filename + '(' + `lineno` + ')'
363 #s = filename + '(' + `lineno` + ')'
365 filename = self.canonic(frame.f_code.co_filename)
364 filename = self.canonic(frame.f_code.co_filename)
366 link = tpl_link % filename
365 link = tpl_link % filename
367
366
368 if frame.f_code.co_name:
367 if frame.f_code.co_name:
369 func = frame.f_code.co_name
368 func = frame.f_code.co_name
370 else:
369 else:
371 func = "<lambda>"
370 func = "<lambda>"
372
371
373 call = ''
372 call = ''
374 if func != '?':
373 if func != '?':
375 if '__args__' in frame.f_locals:
374 if '__args__' in frame.f_locals:
376 args = repr.repr(frame.f_locals['__args__'])
375 args = repr.repr(frame.f_locals['__args__'])
377 else:
376 else:
378 args = '()'
377 args = '()'
379 call = tpl_call % (func, args)
378 call = tpl_call % (func, args)
380
379
381 # The level info should be generated in the same format pdb uses, to
380 # The level info should be generated in the same format pdb uses, to
382 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
381 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
383 if frame is self.curframe:
382 if frame is self.curframe:
384 ret.append('> ')
383 ret.append('> ')
385 else:
384 else:
386 ret.append(' ')
385 ret.append(' ')
387 ret.append('%s(%s)%s\n' % (link,lineno,call))
386 ret.append('%s(%s)%s\n' % (link,lineno,call))
388
387
389 start = lineno - 1 - context//2
388 start = lineno - 1 - context//2
390 lines = linecache.getlines(filename)
389 lines = linecache.getlines(filename)
391 start = max(start, 0)
390 start = max(start, 0)
392 start = min(start, len(lines) - context)
391 start = min(start, len(lines) - context)
393 lines = lines[start : start + context]
392 lines = lines[start : start + context]
394
393
395 for i,line in enumerate(lines):
394 for i,line in enumerate(lines):
396 show_arrow = (start + 1 + i == lineno)
395 show_arrow = (start + 1 + i == lineno)
397 linetpl = (frame is self.curframe or show_arrow) \
396 linetpl = (frame is self.curframe or show_arrow) \
398 and tpl_line_em \
397 and tpl_line_em \
399 or tpl_line
398 or tpl_line
400 ret.append(self.__format_line(linetpl, filename,
399 ret.append(self.__format_line(linetpl, filename,
401 start + 1 + i, line,
400 start + 1 + i, line,
402 arrow = show_arrow) )
401 arrow = show_arrow) )
403
402
404 return ''.join(ret)
403 return ''.join(ret)
405
404
406 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
405 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
407 bp_mark = ""
406 bp_mark = ""
408 bp_mark_color = ""
407 bp_mark_color = ""
409
408
410 scheme = self.color_scheme_table.active_scheme_name
409 scheme = self.color_scheme_table.active_scheme_name
411 new_line, err = self.parser.format2(line, 'str', scheme)
410 new_line, err = self.parser.format2(line, 'str', scheme)
412 if not err: line = new_line
411 if not err: line = new_line
413
412
414 bp = None
413 bp = None
415 if lineno in self.get_file_breaks(filename):
414 if lineno in self.get_file_breaks(filename):
416 bps = self.get_breaks(filename, lineno)
415 bps = self.get_breaks(filename, lineno)
417 bp = bps[-1]
416 bp = bps[-1]
418
417
419 if bp:
418 if bp:
420 Colors = self.color_scheme_table.active_colors
419 Colors = self.color_scheme_table.active_colors
421 bp_mark = str(bp.number)
420 bp_mark = str(bp.number)
422 bp_mark_color = Colors.breakpoint_enabled
421 bp_mark_color = Colors.breakpoint_enabled
423 if not bp.enabled:
422 if not bp.enabled:
424 bp_mark_color = Colors.breakpoint_disabled
423 bp_mark_color = Colors.breakpoint_disabled
425
424
426 numbers_width = 7
425 numbers_width = 7
427 if arrow:
426 if arrow:
428 # This is the line with the error
427 # This is the line with the error
429 pad = numbers_width - len(str(lineno)) - len(bp_mark)
428 pad = numbers_width - len(str(lineno)) - len(bp_mark)
430 if pad >= 3:
429 if pad >= 3:
431 marker = '-'*(pad-3) + '-> '
430 marker = '-'*(pad-3) + '-> '
432 elif pad == 2:
431 elif pad == 2:
433 marker = '> '
432 marker = '> '
434 elif pad == 1:
433 elif pad == 1:
435 marker = '>'
434 marker = '>'
436 else:
435 else:
437 marker = ''
436 marker = ''
438 num = '%s%s' % (marker, str(lineno))
437 num = '%s%s' % (marker, str(lineno))
439 line = tpl_line % (bp_mark_color + bp_mark, num, line)
438 line = tpl_line % (bp_mark_color + bp_mark, num, line)
440 else:
439 else:
441 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
440 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
442 line = tpl_line % (bp_mark_color + bp_mark, num, line)
441 line = tpl_line % (bp_mark_color + bp_mark, num, line)
443
442
444 return line
443 return line
445
444
446 def list_command_pydb(self, arg):
445 def list_command_pydb(self, arg):
447 """List command to use if we have a newer pydb installed"""
446 """List command to use if we have a newer pydb installed"""
448 filename, first, last = OldPdb.parse_list_cmd(self, arg)
447 filename, first, last = OldPdb.parse_list_cmd(self, arg)
449 if filename is not None:
448 if filename is not None:
450 self.print_list_lines(filename, first, last)
449 self.print_list_lines(filename, first, last)
451
450
452 def print_list_lines(self, filename, first, last):
451 def print_list_lines(self, filename, first, last):
453 """The printing (as opposed to the parsing part of a 'list'
452 """The printing (as opposed to the parsing part of a 'list'
454 command."""
453 command."""
455 try:
454 try:
456 Colors = self.color_scheme_table.active_colors
455 Colors = self.color_scheme_table.active_colors
457 ColorsNormal = Colors.Normal
456 ColorsNormal = Colors.Normal
458 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
457 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
459 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
458 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
460 src = []
459 src = []
461 for lineno in range(first, last+1):
460 for lineno in range(first, last+1):
462 line = linecache.getline(filename, lineno)
461 line = linecache.getline(filename, lineno)
463 if not line:
462 if not line:
464 break
463 break
465
464
466 if lineno == self.curframe.f_lineno:
465 if lineno == self.curframe.f_lineno:
467 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
466 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
468 else:
467 else:
469 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
468 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
470
469
471 src.append(line)
470 src.append(line)
472 self.lineno = lineno
471 self.lineno = lineno
473
472
474 print >>Term.cout, ''.join(src)
473 print >>Term.cout, ''.join(src)
475
474
476 except KeyboardInterrupt:
475 except KeyboardInterrupt:
477 pass
476 pass
478
477
479 def do_list(self, arg):
478 def do_list(self, arg):
480 self.lastcmd = 'list'
479 self.lastcmd = 'list'
481 last = None
480 last = None
482 if arg:
481 if arg:
483 try:
482 try:
484 x = eval(arg, {}, {})
483 x = eval(arg, {}, {})
485 if type(x) == type(()):
484 if type(x) == type(()):
486 first, last = x
485 first, last = x
487 first = int(first)
486 first = int(first)
488 last = int(last)
487 last = int(last)
489 if last < first:
488 if last < first:
490 # Assume it's a count
489 # Assume it's a count
491 last = first + last
490 last = first + last
492 else:
491 else:
493 first = max(1, int(x) - 5)
492 first = max(1, int(x) - 5)
494 except:
493 except:
495 print '*** Error in argument:', `arg`
494 print '*** Error in argument:', `arg`
496 return
495 return
497 elif self.lineno is None:
496 elif self.lineno is None:
498 first = max(1, self.curframe.f_lineno - 5)
497 first = max(1, self.curframe.f_lineno - 5)
499 else:
498 else:
500 first = self.lineno + 1
499 first = self.lineno + 1
501 if last is None:
500 if last is None:
502 last = first + 10
501 last = first + 10
503 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
502 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
504
503
505 # vds: >>
504 # vds: >>
506 lineno = first
505 lineno = first
507 filename = self.curframe.f_code.co_filename
506 filename = self.curframe.f_code.co_filename
508 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
507 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
509 # vds: <<
508 # vds: <<
510
509
511 do_l = do_list
510 do_l = do_list
512
511
513 def do_pdef(self, arg):
512 def do_pdef(self, arg):
514 """The debugger interface to magic_pdef"""
513 """The debugger interface to magic_pdef"""
515 namespaces = [('Locals', self.curframe.f_locals),
514 namespaces = [('Locals', self.curframe.f_locals),
516 ('Globals', self.curframe.f_globals)]
515 ('Globals', self.curframe.f_globals)]
517 __IPYTHON__.magic_pdef(arg, namespaces=namespaces)
516 __IPYTHON__.magic_pdef(arg, namespaces=namespaces)
518
517
519 def do_pdoc(self, arg):
518 def do_pdoc(self, arg):
520 """The debugger interface to magic_pdoc"""
519 """The debugger interface to magic_pdoc"""
521 namespaces = [('Locals', self.curframe.f_locals),
520 namespaces = [('Locals', self.curframe.f_locals),
522 ('Globals', self.curframe.f_globals)]
521 ('Globals', self.curframe.f_globals)]
523 __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)
522 __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)
524
523
525 def do_pinfo(self, arg):
524 def do_pinfo(self, arg):
526 """The debugger equivalant of ?obj"""
525 """The debugger equivalant of ?obj"""
527 namespaces = [('Locals', self.curframe.f_locals),
526 namespaces = [('Locals', self.curframe.f_locals),
528 ('Globals', self.curframe.f_globals)]
527 ('Globals', self.curframe.f_globals)]
529 __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
528 __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
@@ -1,109 +1,143 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Color schemes for exception handling code in IPython.
3 Color schemes for exception handling code in IPython.
4
4
5 $Id: Prompts.py 638 2005-07-18 03:01:41Z fperez $"""
5 $Id: Prompts.py 638 2005-07-18 03:01:41Z fperez $"""
6
6
7 #*****************************************************************************
7 #*****************************************************************************
8 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #*****************************************************************************
12 #*****************************************************************************
13
13
14 from IPython import Release
14 from IPython import Release
15 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __author__ = '%s <%s>' % Release.authors['Fernando']
16 __license__ = Release.license
16 __license__ = Release.license
17 __version__ = Release.version
17 __version__ = Release.version
18
18
19 #****************************************************************************
19 #****************************************************************************
20 # Required modules
20 # Required modules
21 from IPython.ColorANSI import ColorSchemeTable, TermColors, ColorScheme
21 from IPython.ColorANSI import ColorSchemeTable, TermColors, ColorScheme
22
22
23 ExceptionColors = ColorSchemeTable()
23 def exception_colors():
24
24 """Return a color table with fields for exception reporting.
25 # Populate it with color schemes
25
26 C = TermColors # shorthand and local lookup
26 The table is an instance of ColorSchemeTable with schemes added for
27 ExceptionColors.add_scheme(ColorScheme(
27 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
28 'NoColor',
28 in.
29 # The color to be used for the top line
29
30 topline = C.NoColor,
30 Examples:
31
31
32 # The colors to be used in the traceback
32 >>> ec = exception_colors()
33 filename = C.NoColor,
33 >>> ec.active_scheme_name
34 lineno = C.NoColor,
34 ''
35 name = C.NoColor,
35 >>> print ec.active_colors
36 vName = C.NoColor,
36 None
37 val = C.NoColor,
37
38 em = C.NoColor,
38 Now we activate a color scheme:
39
39 >>> ec.set_active_scheme('NoColor')
40 # Emphasized colors for the last frame of the traceback
40 >>> ec.active_scheme_name
41 normalEm = C.NoColor,
41 'NoColor'
42 filenameEm = C.NoColor,
42 >>> ec.active_colors.keys()
43 linenoEm = C.NoColor,
43 ['em', 'caret', '__allownew', 'name', 'val', 'vName', 'Normal', 'normalEm',
44 nameEm = C.NoColor,
44 'filename', 'linenoEm', 'excName', 'lineno', 'valEm', 'filenameEm',
45 valEm = C.NoColor,
45 'nameEm', 'line', 'topline']
46
46 """
47 # Colors for printing the exception
48 excName = C.NoColor,
49 line = C.NoColor,
50 caret = C.NoColor,
51 Normal = C.NoColor
52 ))
53
54 # make some schemes as instances so we can copy them for modification easily
55 ExceptionColors.add_scheme(ColorScheme(
56 'Linux',
57 # The color to be used for the top line
58 topline = C.LightRed,
59
60 # The colors to be used in the traceback
61 filename = C.Green,
62 lineno = C.Green,
63 name = C.Purple,
64 vName = C.Cyan,
65 val = C.Green,
66 em = C.LightCyan,
67
68 # Emphasized colors for the last frame of the traceback
69 normalEm = C.LightCyan,
70 filenameEm = C.LightGreen,
71 linenoEm = C.LightGreen,
72 nameEm = C.LightPurple,
73 valEm = C.LightBlue,
74
75 # Colors for printing the exception
76 excName = C.LightRed,
77 line = C.Yellow,
78 caret = C.White,
79 Normal = C.Normal
80 ))
81
82 # For light backgrounds, swap dark/light colors
83 ExceptionColors.add_scheme(ColorScheme(
84 'LightBG',
85 # The color to be used for the top line
86 topline = C.Red,
87
47
88 # The colors to be used in the traceback
48 ex_colors = ColorSchemeTable()
89 filename = C.LightGreen,
49
90 lineno = C.LightGreen,
50 # Populate it with color schemes
91 name = C.LightPurple,
51 C = TermColors # shorthand and local lookup
92 vName = C.Cyan,
52 ex_colors.add_scheme(ColorScheme(
93 val = C.LightGreen,
53 'NoColor',
94 em = C.Cyan,
54 # The color to be used for the top line
95
55 topline = C.NoColor,
96 # Emphasized colors for the last frame of the traceback
56
97 normalEm = C.Cyan,
57 # The colors to be used in the traceback
98 filenameEm = C.Green,
58 filename = C.NoColor,
99 linenoEm = C.Green,
59 lineno = C.NoColor,
100 nameEm = C.Purple,
60 name = C.NoColor,
101 valEm = C.Blue,
61 vName = C.NoColor,
102
62 val = C.NoColor,
103 # Colors for printing the exception
63 em = C.NoColor,
104 excName = C.Red,
64
105 #line = C.Brown, # brown often is displayed as yellow
65 # Emphasized colors for the last frame of the traceback
106 line = C.Red,
66 normalEm = C.NoColor,
107 caret = C.Normal,
67 filenameEm = C.NoColor,
108 Normal = C.Normal
68 linenoEm = C.NoColor,
109 ))
69 nameEm = C.NoColor,
70 valEm = C.NoColor,
71
72 # Colors for printing the exception
73 excName = C.NoColor,
74 line = C.NoColor,
75 caret = C.NoColor,
76 Normal = C.NoColor
77 ))
78
79 # make some schemes as instances so we can copy them for modification easily
80 ex_colors.add_scheme(ColorScheme(
81 'Linux',
82 # The color to be used for the top line
83 topline = C.LightRed,
84
85 # The colors to be used in the traceback
86 filename = C.Green,
87 lineno = C.Green,
88 name = C.Purple,
89 vName = C.Cyan,
90 val = C.Green,
91 em = C.LightCyan,
92
93 # Emphasized colors for the last frame of the traceback
94 normalEm = C.LightCyan,
95 filenameEm = C.LightGreen,
96 linenoEm = C.LightGreen,
97 nameEm = C.LightPurple,
98 valEm = C.LightBlue,
99
100 # Colors for printing the exception
101 excName = C.LightRed,
102 line = C.Yellow,
103 caret = C.White,
104 Normal = C.Normal
105 ))
106
107 # For light backgrounds, swap dark/light colors
108 ex_colors.add_scheme(ColorScheme(
109 'LightBG',
110 # The color to be used for the top line
111 topline = C.Red,
112
113 # The colors to be used in the traceback
114 filename = C.LightGreen,
115 lineno = C.LightGreen,
116 name = C.LightPurple,
117 vName = C.Cyan,
118 val = C.LightGreen,
119 em = C.Cyan,
120
121 # Emphasized colors for the last frame of the traceback
122 normalEm = C.Cyan,
123 filenameEm = C.Green,
124 linenoEm = C.Green,
125 nameEm = C.Purple,
126 valEm = C.Blue,
127
128 # Colors for printing the exception
129 excName = C.Red,
130 #line = C.Brown, # brown often is displayed as yellow
131 line = C.Red,
132 caret = C.Normal,
133 Normal = C.Normal
134 ))
135
136 return ex_colors
137
138
139 # For backwards compatibility, keep around a single global object. Note that
140 # this should NOT be used, the factory function should be used instead, since
141 # these objects are stateful and it's very easy to get strange bugs if any code
142 # modifies the module-level object's state.
143 ExceptionColors = exception_colors()
@@ -1,1018 +1,1062 b''
1 # encoding: utf-8
1 # -*- coding: utf-8 -*-
2
3 """
2 """
4 ultraTB.py -- Spice up your tracebacks!
3 ultraTB.py -- Spice up your tracebacks!
5
4
6 * ColorTB
5 * ColorTB
7 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
8 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
9 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
10 text editor.
9 text editor.
11
10
12 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
13 import sys,ultraTB
12 import sys,ultraTB
14 sys.excepthook = ultraTB.ColorTB()
13 sys.excepthook = ultraTB.ColorTB()
15
14
16 * VerboseTB
15 * VerboseTB
17 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
18 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
19 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
20 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,
21 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
22 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.
23 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.
24
23
25 Note:
24 Note:
26
25
27 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
28 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
29 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
30 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
31 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
32 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
33
32
34 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
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
36 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
37 Verbose).
36 Verbose).
38
37
39
38
40 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
41 import sys,ultraTB
40 import sys,ultraTB
42 sys.excepthook = ultraTB.VerboseTB()
41 sys.excepthook = ultraTB.VerboseTB()
43
42
44 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
45 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
46
45
47 * Color schemes
46 * Color schemes
48 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
49 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
50
49
51 - 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
52 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
53
52
54 - 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
55 or very dark background).
54 or very dark background).
56
55
57 - 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
58 in light background terminals.
57 in light background terminals.
59
58
60 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
61 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
62 possible inclusion in future releases.
61 possible inclusion in future releases.
63
62
64 $Id: ultraTB.py 2480 2007-07-06 19:33:43Z fperez $"""
63 $Id: ultraTB.py 2908 2007-12-30 21:07:46Z vivainio $"""
65
66 __docformat__ = "restructuredtext en"
67
64
68 #-------------------------------------------------------------------------------
65 #*****************************************************************************
69 # Copyright (C) 2008 The IPython Development Team
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
70 #
68 #
71 # 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
72 # the file COPYING, distributed as part of this software.
70 # the file COPYING, distributed as part of this software.
73 #-------------------------------------------------------------------------------
71 #*****************************************************************************
74
75 #-------------------------------------------------------------------------------
76 # Imports
77 #-------------------------------------------------------------------------------
78
72
79 from IPython import Release
73 from IPython import Release
80 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
81 Release.authors['Fernando'])
75 Release.authors['Fernando'])
82 __license__ = Release.license
76 __license__ = Release.license
83
77
84 # Required modules
78 # Required modules
85 import inspect
79 import inspect
86 import keyword
80 import keyword
87 import linecache
81 import linecache
88 import os
82 import os
89 import pydoc
83 import pydoc
90 import re
84 import re
91 import string
85 import string
92 import sys
86 import sys
93 import time
87 import time
94 import tokenize
88 import tokenize
95 import traceback
89 import traceback
96 import types
90 import types
97
91
98 # For purposes of monkeypatching inspect to fix a bug in it.
92 # For purposes of monkeypatching inspect to fix a bug in it.
99 from inspect import getsourcefile, getfile, getmodule,\
93 from inspect import getsourcefile, getfile, getmodule,\
100 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
101
95
102
96
103 # IPython's own modules
97 # IPython's own modules
104 # Modified pdb which doesn't damage IPython's readline handling
98 # Modified pdb which doesn't damage IPython's readline handling
105 from IPython import Debugger, PyColorize
99 from IPython import Debugger, PyColorize
106 from IPython.ipstruct import Struct
100 from IPython.ipstruct import Struct
107 from IPython.excolors import ExceptionColors
101 from IPython.excolors import exception_colors
108 from IPython.genutils import Term,uniq_stable,error,info
102 from IPython.genutils import Term,uniq_stable,error,info
109
103
110 # Globals
104 # Globals
111 # amount of space to put line numbers before verbose tracebacks
105 # amount of space to put line numbers before verbose tracebacks
112 INDENT_SIZE = 8
106 INDENT_SIZE = 8
113
107
114 # Default color scheme. This is used, for example, by the traceback
108 # Default color scheme. This is used, for example, by the traceback
115 # 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
116 # value is used, but havinga module global makes this functionality available
110 # value is used, but havinga module global makes this functionality available
117 # to users of ultraTB who are NOT running inside ipython.
111 # to users of ultraTB who are NOT running inside ipython.
118 DEFAULT_SCHEME = 'NoColor'
112 DEFAULT_SCHEME = 'NoColor'
119
113
120 #---------------------------------------------------------------------------
114 #---------------------------------------------------------------------------
121 # Code begins
115 # Code begins
122
116
123 # Utility functions
117 # Utility functions
124 def inspect_error():
118 def inspect_error():
125 """Print a message about internal inspect errors.
119 """Print a message about internal inspect errors.
126
120
127 These are unfortunately quite common."""
121 These are unfortunately quite common."""
128
122
129 error('Internal Python error in the inspect module.\n'
123 error('Internal Python error in the inspect module.\n'
130 'Below is the traceback from this internal error.\n')
124 'Below is the traceback from this internal error.\n')
131
125
132
126
133 def findsource(object):
127 def findsource(object):
134 """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.
135
129
136 The argument may be a module, class, method, function, traceback, frame,
130 The argument may be a module, class, method, function, traceback, frame,
137 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
138 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
139 is raised if the source code cannot be retrieved.
133 is raised if the source code cannot be retrieved.
140
134
141 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."""
142
136
143 file = getsourcefile(object) or getfile(object)
137 file = getsourcefile(object) or getfile(object)
144 module = getmodule(object, file)
138 # If the object is a frame, then trying to get the globals dict from its
145 if module:
139 # module won't work. Instead, the frame object itself has the globals
146 lines = linecache.getlines(file, module.__dict__)
140 # dictionary.
141 globals_dict = None
142 if inspect.isframe(object):
143 # XXX: can this ever be false?
144 globals_dict = object.f_globals
147 else:
145 else:
148 lines = linecache.getlines(file)
146 module = getmodule(object, file)
147 if module:
148 globals_dict = module.__dict__
149 lines = linecache.getlines(file, globals_dict)
149 if not lines:
150 if not lines:
150 raise IOError('could not get source code')
151 raise IOError('could not get source code')
151
152
152 if ismodule(object):
153 if ismodule(object):
153 return lines, 0
154 return lines, 0
154
155
155 if isclass(object):
156 if isclass(object):
156 name = object.__name__
157 name = object.__name__
157 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
158 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
158 # make some effort to find the best matching class definition:
159 # make some effort to find the best matching class definition:
159 # use the one with the least indentation, which is the one
160 # use the one with the least indentation, which is the one
160 # that's most probably not inside a function definition.
161 # that's most probably not inside a function definition.
161 candidates = []
162 candidates = []
162 for i in range(len(lines)):
163 for i in range(len(lines)):
163 match = pat.match(lines[i])
164 match = pat.match(lines[i])
164 if match:
165 if match:
165 # if it's at toplevel, it's already the best one
166 # if it's at toplevel, it's already the best one
166 if lines[i][0] == 'c':
167 if lines[i][0] == 'c':
167 return lines, i
168 return lines, i
168 # else add whitespace to candidate list
169 # else add whitespace to candidate list
169 candidates.append((match.group(1), i))
170 candidates.append((match.group(1), i))
170 if candidates:
171 if candidates:
171 # this will sort by whitespace, and by line number,
172 # this will sort by whitespace, and by line number,
172 # less whitespace first
173 # less whitespace first
173 candidates.sort()
174 candidates.sort()
174 return lines, candidates[0][1]
175 return lines, candidates[0][1]
175 else:
176 else:
176 raise IOError('could not find class definition')
177 raise IOError('could not find class definition')
177
178
178 if ismethod(object):
179 if ismethod(object):
179 object = object.im_func
180 object = object.im_func
180 if isfunction(object):
181 if isfunction(object):
181 object = object.func_code
182 object = object.func_code
182 if istraceback(object):
183 if istraceback(object):
183 object = object.tb_frame
184 object = object.tb_frame
184 if isframe(object):
185 if isframe(object):
185 object = object.f_code
186 object = object.f_code
186 if iscode(object):
187 if iscode(object):
187 if not hasattr(object, 'co_firstlineno'):
188 if not hasattr(object, 'co_firstlineno'):
188 raise IOError('could not find function definition')
189 raise IOError('could not find function definition')
189 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
190 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
190 pmatch = pat.match
191 pmatch = pat.match
191 # fperez - fix: sometimes, co_firstlineno can give a number larger than
192 # fperez - fix: sometimes, co_firstlineno can give a number larger than
192 # the length of lines, which causes an error. Safeguard against that.
193 # the length of lines, which causes an error. Safeguard against that.
193 lnum = min(object.co_firstlineno,len(lines))-1
194 lnum = min(object.co_firstlineno,len(lines))-1
194 while lnum > 0:
195 while lnum > 0:
195 if pmatch(lines[lnum]): break
196 if pmatch(lines[lnum]): break
196 lnum -= 1
197 lnum -= 1
197
198
198 return lines, lnum
199 return lines, lnum
199 raise IOError('could not find code object')
200 raise IOError('could not find code object')
200
201
201 # 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
202 if sys.version_info[:2] >= (2,5):
203 if sys.version_info[:2] >= (2,5):
203 inspect.findsource = findsource
204 inspect.findsource = findsource
204
205
206 def fix_frame_records_filenames(records):
207 """Try to fix the filenames in each record from inspect.getinnerframes().
208
209 Particularly, modules loaded from within zip files have useless filenames
210 attached to their code object, and inspect.getinnerframes() just uses it.
211 """
212 fixed_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
215 # be better.
216 better_fn = frame.f_globals.get('__file__', None)
217 if isinstance(better_fn, str):
218 # Check the type just in case someone did something weird with
219 # __file__. It might also be None if the error occurred during
220 # import.
221 filename = better_fn
222 fixed_records.append((frame, filename, line_no, func_name, lines, index))
223 return fixed_records
224
225
205 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
226 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
206 import linecache
227 import linecache
207 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
228 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
208
229
209 records = inspect.getinnerframes(etb, context)
230 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
210
231
211 # 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
212 # 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
213 # console)
234 # console)
214 rec_check = records[tb_offset:]
235 rec_check = records[tb_offset:]
215 try:
236 try:
216 rname = rec_check[0][1]
237 rname = rec_check[0][1]
217 if rname == '<ipython console>' or rname.endswith('<string>'):
238 if rname == '<ipython console>' or rname.endswith('<string>'):
218 return rec_check
239 return rec_check
219 except IndexError:
240 except IndexError:
220 pass
241 pass
221
242
222 aux = traceback.extract_tb(etb)
243 aux = traceback.extract_tb(etb)
223 assert len(records) == len(aux)
244 assert len(records) == len(aux)
224 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
245 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
225 maybeStart = lnum-1 - context//2
246 maybeStart = lnum-1 - context//2
226 start = max(maybeStart, 0)
247 start = max(maybeStart, 0)
227 end = start + context
248 end = start + context
228 lines = linecache.getlines(file)[start:end]
249 lines = linecache.getlines(file)[start:end]
229 # pad with empty lines if necessary
250 # pad with empty lines if necessary
230 if maybeStart < 0:
251 if maybeStart < 0:
231 lines = (['\n'] * -maybeStart) + lines
252 lines = (['\n'] * -maybeStart) + lines
232 if len(lines) < context:
253 if len(lines) < context:
233 lines += ['\n'] * (context - len(lines))
254 lines += ['\n'] * (context - len(lines))
234 buf = list(records[i])
255 buf = list(records[i])
235 buf[LNUM_POS] = lnum
256 buf[LNUM_POS] = lnum
236 buf[INDEX_POS] = lnum - 1 - start
257 buf[INDEX_POS] = lnum - 1 - start
237 buf[LINES_POS] = lines
258 buf[LINES_POS] = lines
238 records[i] = tuple(buf)
259 records[i] = tuple(buf)
239 return records[tb_offset:]
260 return records[tb_offset:]
240
261
241 # Helper function -- largely belongs to VerboseTB, but we need the same
262 # Helper function -- largely belongs to VerboseTB, but we need the same
242 # 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
243 # 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
244 # (SyntaxErrors have to be treated specially because they have no traceback)
265 # (SyntaxErrors have to be treated specially because they have no traceback)
245
266
246 _parser = PyColorize.Parser()
267 _parser = PyColorize.Parser()
247
268
248 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
269 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
249 numbers_width = INDENT_SIZE - 1
270 numbers_width = INDENT_SIZE - 1
250 res = []
271 res = []
251 i = lnum - index
272 i = lnum - index
252
273
253 # This lets us get fully syntax-highlighted tracebacks.
274 # This lets us get fully syntax-highlighted tracebacks.
254 if scheme is None:
275 if scheme is None:
255 try:
276 try:
256 scheme = __IPYTHON__.rc.colors
277 scheme = __IPYTHON__.rc.colors
257 except:
278 except:
258 scheme = DEFAULT_SCHEME
279 scheme = DEFAULT_SCHEME
259 _line_format = _parser.format2
280 _line_format = _parser.format2
260
281
261 for line in lines:
282 for line in lines:
262 new_line, err = _line_format(line,'str',scheme)
283 new_line, err = _line_format(line,'str',scheme)
263 if not err: line = new_line
284 if not err: line = new_line
264
285
265 if i == lnum:
286 if i == lnum:
266 # This is the line with the error
287 # This is the line with the error
267 pad = numbers_width - len(str(i))
288 pad = numbers_width - len(str(i))
268 if pad >= 3:
289 if pad >= 3:
269 marker = '-'*(pad-3) + '-> '
290 marker = '-'*(pad-3) + '-> '
270 elif pad == 2:
291 elif pad == 2:
271 marker = '> '
292 marker = '> '
272 elif pad == 1:
293 elif pad == 1:
273 marker = '>'
294 marker = '>'
274 else:
295 else:
275 marker = ''
296 marker = ''
276 num = marker + str(i)
297 num = marker + str(i)
277 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
278 Colors.line, line, Colors.Normal)
299 Colors.line, line, Colors.Normal)
279 else:
300 else:
280 num = '%*s' % (numbers_width,i)
301 num = '%*s' % (numbers_width,i)
281 line = '%s%s%s %s' %(Colors.lineno, num,
302 line = '%s%s%s %s' %(Colors.lineno, num,
282 Colors.Normal, line)
303 Colors.Normal, line)
283
304
284 res.append(line)
305 res.append(line)
285 if lvals and i == lnum:
306 if lvals and i == lnum:
286 res.append(lvals + '\n')
307 res.append(lvals + '\n')
287 i = i + 1
308 i = i + 1
288 return res
309 return res
289
310
290
311
291 #---------------------------------------------------------------------------
312 #---------------------------------------------------------------------------
292 # Module classes
313 # Module classes
293 class TBTools:
314 class TBTools:
294 """Basic tools used by all traceback printer classes."""
315 """Basic tools used by all traceback printer classes."""
295
316
296 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
317 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
297 # Whether to call the interactive pdb debugger after printing
318 # Whether to call the interactive pdb debugger after printing
298 # tracebacks or not
319 # tracebacks or not
299 self.call_pdb = call_pdb
320 self.call_pdb = call_pdb
300
321
301 # Create color table
322 # Create color table
302 self.color_scheme_table = ExceptionColors
323 self.color_scheme_table = exception_colors()
303
324
304 self.set_colors(color_scheme)
325 self.set_colors(color_scheme)
305 self.old_scheme = color_scheme # save initial value for toggles
326 self.old_scheme = color_scheme # save initial value for toggles
306
327
307 if call_pdb:
328 if call_pdb:
308 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
329 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
309 else:
330 else:
310 self.pdb = None
331 self.pdb = None
311
332
312 def set_colors(self,*args,**kw):
333 def set_colors(self,*args,**kw):
313 """Shorthand access to the color table scheme selector method."""
334 """Shorthand access to the color table scheme selector method."""
314
335
315 # Set own color table
336 # Set own color table
316 self.color_scheme_table.set_active_scheme(*args,**kw)
337 self.color_scheme_table.set_active_scheme(*args,**kw)
317 # for convenience, set Colors to the active scheme
338 # for convenience, set Colors to the active scheme
318 self.Colors = self.color_scheme_table.active_colors
339 self.Colors = self.color_scheme_table.active_colors
319 # Also set colors of debugger
340 # Also set colors of debugger
320 if hasattr(self,'pdb') and self.pdb is not None:
341 if hasattr(self,'pdb') and self.pdb is not None:
321 self.pdb.set_colors(*args,**kw)
342 self.pdb.set_colors(*args,**kw)
322
343
323 def color_toggle(self):
344 def color_toggle(self):
324 """Toggle between the currently active color scheme and NoColor."""
345 """Toggle between the currently active color scheme and NoColor."""
325
346
326 if self.color_scheme_table.active_scheme_name == 'NoColor':
347 if self.color_scheme_table.active_scheme_name == 'NoColor':
327 self.color_scheme_table.set_active_scheme(self.old_scheme)
348 self.color_scheme_table.set_active_scheme(self.old_scheme)
328 self.Colors = self.color_scheme_table.active_colors
349 self.Colors = self.color_scheme_table.active_colors
329 else:
350 else:
330 self.old_scheme = self.color_scheme_table.active_scheme_name
351 self.old_scheme = self.color_scheme_table.active_scheme_name
331 self.color_scheme_table.set_active_scheme('NoColor')
352 self.color_scheme_table.set_active_scheme('NoColor')
332 self.Colors = self.color_scheme_table.active_colors
353 self.Colors = self.color_scheme_table.active_colors
333
354
334 #---------------------------------------------------------------------------
355 #---------------------------------------------------------------------------
335 class ListTB(TBTools):
356 class ListTB(TBTools):
336 """Print traceback information from a traceback list, with optional color.
357 """Print traceback information from a traceback list, with optional color.
337
358
338 Calling: requires 3 arguments:
359 Calling: requires 3 arguments:
339 (etype, evalue, elist)
360 (etype, evalue, elist)
340 as would be obtained by:
361 as would be obtained by:
341 etype, evalue, tb = sys.exc_info()
362 etype, evalue, tb = sys.exc_info()
342 if tb:
363 if tb:
343 elist = traceback.extract_tb(tb)
364 elist = traceback.extract_tb(tb)
344 else:
365 else:
345 elist = None
366 elist = None
346
367
347 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
348 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
349 standard library).
370 standard library).
350
371
351 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
352 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."""
353
374
354 def __init__(self,color_scheme = 'NoColor'):
375 def __init__(self,color_scheme = 'NoColor'):
355 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
376 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
356
377
357 def __call__(self, etype, value, elist):
378 def __call__(self, etype, value, elist):
358 Term.cout.flush()
379 Term.cout.flush()
359 Term.cerr.flush()
360 print >> Term.cerr, self.text(etype,value,elist)
380 print >> Term.cerr, self.text(etype,value,elist)
381 Term.cerr.flush()
361
382
362 def text(self,etype, value, elist,context=5):
383 def text(self,etype, value, elist,context=5):
363 """Return a color formatted string with the traceback info."""
384 """Return a color formatted string with the traceback info."""
364
385
365 Colors = self.Colors
386 Colors = self.Colors
366 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
387 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
367 if elist:
388 if elist:
368 out_string.append('Traceback %s(most recent call last)%s:' % \
389 out_string.append('Traceback %s(most recent call last)%s:' % \
369 (Colors.normalEm, Colors.Normal) + '\n')
390 (Colors.normalEm, Colors.Normal) + '\n')
370 out_string.extend(self._format_list(elist))
391 out_string.extend(self._format_list(elist))
371 lines = self._format_exception_only(etype, value)
392 lines = self._format_exception_only(etype, value)
372 for line in lines[:-1]:
393 for line in lines[:-1]:
373 out_string.append(" "+line)
394 out_string.append(" "+line)
374 out_string.append(lines[-1])
395 out_string.append(lines[-1])
375 return ''.join(out_string)
396 return ''.join(out_string)
376
397
377 def _format_list(self, extracted_list):
398 def _format_list(self, extracted_list):
378 """Format a list of traceback entry tuples for printing.
399 """Format a list of traceback entry tuples for printing.
379
400
380 Given a list of tuples as returned by extract_tb() or
401 Given a list of tuples as returned by extract_tb() or
381 extract_stack(), return a list of strings ready for printing.
402 extract_stack(), return a list of strings ready for printing.
382 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
383 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;
384 the strings may contain internal newlines as well, for those items
405 the strings may contain internal newlines as well, for those items
385 whose source text line is not None.
406 whose source text line is not None.
386
407
387 Lifted almost verbatim from traceback.py
408 Lifted almost verbatim from traceback.py
388 """
409 """
389
410
390 Colors = self.Colors
411 Colors = self.Colors
391 list = []
412 list = []
392 for filename, lineno, name, line in extracted_list[:-1]:
413 for filename, lineno, name, line in extracted_list[:-1]:
393 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' % \
394 (Colors.filename, filename, Colors.Normal,
415 (Colors.filename, filename, Colors.Normal,
395 Colors.lineno, lineno, Colors.Normal,
416 Colors.lineno, lineno, Colors.Normal,
396 Colors.name, name, Colors.Normal)
417 Colors.name, name, Colors.Normal)
397 if line:
418 if line:
398 item = item + ' %s\n' % line.strip()
419 item = item + ' %s\n' % line.strip()
399 list.append(item)
420 list.append(item)
400 # Emphasize the last entry
421 # Emphasize the last entry
401 filename, lineno, name, line = extracted_list[-1]
422 filename, lineno, name, line = extracted_list[-1]
402 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' % \
403 (Colors.normalEm,
424 (Colors.normalEm,
404 Colors.filenameEm, filename, Colors.normalEm,
425 Colors.filenameEm, filename, Colors.normalEm,
405 Colors.linenoEm, lineno, Colors.normalEm,
426 Colors.linenoEm, lineno, Colors.normalEm,
406 Colors.nameEm, name, Colors.normalEm,
427 Colors.nameEm, name, Colors.normalEm,
407 Colors.Normal)
428 Colors.Normal)
408 if line:
429 if line:
409 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
430 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
410 Colors.Normal)
431 Colors.Normal)
411 list.append(item)
432 list.append(item)
412 return list
433 return list
413
434
414 def _format_exception_only(self, etype, value):
435 def _format_exception_only(self, etype, value):
415 """Format the exception part of a traceback.
436 """Format the exception part of a traceback.
416
437
417 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
418 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
419 in a newline. Normally, the list contains a single string; however,
440 in a newline. Normally, the list contains a single string; however,
420 for SyntaxError exceptions, it contains several lines that (when
441 for SyntaxError exceptions, it contains several lines that (when
421 printed) display detailed information about where the syntax error
442 printed) display detailed information about where the syntax error
422 occurred. The message indicating which exception occurred is the
443 occurred. The message indicating which exception occurred is the
423 always last string in the list.
444 always last string in the list.
424
445
425 Also lifted nearly verbatim from traceback.py
446 Also lifted nearly verbatim from traceback.py
426 """
447 """
427
448
449 have_filedata = False
428 Colors = self.Colors
450 Colors = self.Colors
429 list = []
451 list = []
430 try:
452 try:
431 stype = Colors.excName + etype.__name__ + Colors.Normal
453 stype = Colors.excName + etype.__name__ + Colors.Normal
432 except AttributeError:
454 except AttributeError:
433 stype = etype # String exceptions don't get special coloring
455 stype = etype # String exceptions don't get special coloring
434 if value is None:
456 if value is None:
435 list.append( str(stype) + '\n')
457 list.append( str(stype) + '\n')
436 else:
458 else:
437 if etype is SyntaxError:
459 if etype is SyntaxError:
438 try:
460 try:
439 msg, (filename, lineno, offset, line) = value
461 msg, (filename, lineno, offset, line) = value
440 except:
462 except:
441 pass
463 have_filedata = False
442 else:
464 else:
465 have_filedata = True
443 #print 'filename is',filename # dbg
466 #print 'filename is',filename # dbg
444 if not filename: filename = "<string>"
467 if not filename: filename = "<string>"
445 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
446 (Colors.normalEm,
469 (Colors.normalEm,
447 Colors.filenameEm, filename, Colors.normalEm,
470 Colors.filenameEm, filename, Colors.normalEm,
448 Colors.linenoEm, lineno, Colors.Normal ))
471 Colors.linenoEm, lineno, Colors.Normal ))
449 if line is not None:
472 if line is not None:
450 i = 0
473 i = 0
451 while i < len(line) and line[i].isspace():
474 while i < len(line) and line[i].isspace():
452 i = i+1
475 i = i+1
453 list.append('%s %s%s\n' % (Colors.line,
476 list.append('%s %s%s\n' % (Colors.line,
454 line.strip(),
477 line.strip(),
455 Colors.Normal))
478 Colors.Normal))
456 if offset is not None:
479 if offset is not None:
457 s = ' '
480 s = ' '
458 for c in line[i:offset-1]:
481 for c in line[i:offset-1]:
459 if c.isspace():
482 if c.isspace():
460 s = s + c
483 s = s + c
461 else:
484 else:
462 s = s + ' '
485 s = s + ' '
463 list.append('%s%s^%s\n' % (Colors.caret, s,
486 list.append('%s%s^%s\n' % (Colors.caret, s,
464 Colors.Normal) )
487 Colors.Normal) )
465 value = msg
488 value = msg
466 s = self._some_str(value)
489 s = self._some_str(value)
467 if s:
490 if s:
468 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
491 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
469 Colors.Normal, s))
492 Colors.Normal, s))
470 else:
493 else:
471 list.append('%s\n' % str(stype))
494 list.append('%s\n' % str(stype))
495
496 # vds:>>
497 if have_filedata:
498 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
499 # vds:<<
500
472 return list
501 return list
473
502
474 def _some_str(self, value):
503 def _some_str(self, value):
475 # Lifted from traceback.py
504 # Lifted from traceback.py
476 try:
505 try:
477 return str(value)
506 return str(value)
478 except:
507 except:
479 return '<unprintable %s object>' % type(value).__name__
508 return '<unprintable %s object>' % type(value).__name__
480
509
481 #----------------------------------------------------------------------------
510 #----------------------------------------------------------------------------
482 class VerboseTB(TBTools):
511 class VerboseTB(TBTools):
483 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
512 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
484 of HTML. Requires inspect and pydoc. Crazy, man.
513 of HTML. Requires inspect and pydoc. Crazy, man.
485
514
486 Modified version which optionally strips the topmost entries from the
515 Modified version which optionally strips the topmost entries from the
487 traceback, to be used with alternate interpreters (because their own code
516 traceback, to be used with alternate interpreters (because their own code
488 would appear in the traceback)."""
517 would appear in the traceback)."""
489
518
490 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
519 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
491 call_pdb = 0, include_vars=1):
520 call_pdb = 0, include_vars=1):
492 """Specify traceback offset, headers and color scheme.
521 """Specify traceback offset, headers and color scheme.
493
522
494 Define how many frames to drop from the tracebacks. Calling it with
523 Define how many frames to drop from the tracebacks. Calling it with
495 tb_offset=1 allows use of this handler in interpreters which will have
524 tb_offset=1 allows use of this handler in interpreters which will have
496 their own code at the top of the traceback (VerboseTB will first
525 their own code at the top of the traceback (VerboseTB will first
497 remove that frame before printing the traceback info)."""
526 remove that frame before printing the traceback info)."""
498 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
527 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
499 self.tb_offset = tb_offset
528 self.tb_offset = tb_offset
500 self.long_header = long_header
529 self.long_header = long_header
501 self.include_vars = include_vars
530 self.include_vars = include_vars
502
531
503 def text(self, etype, evalue, etb, context=5):
532 def text(self, etype, evalue, etb, context=5):
504 """Return a nice text document describing the traceback."""
533 """Return a nice text document describing the traceback."""
505
534
506 # some locals
535 # some locals
507 try:
536 try:
508 etype = etype.__name__
537 etype = etype.__name__
509 except AttributeError:
538 except AttributeError:
510 pass
539 pass
511 Colors = self.Colors # just a shorthand + quicker name lookup
540 Colors = self.Colors # just a shorthand + quicker name lookup
512 ColorsNormal = Colors.Normal # used a lot
541 ColorsNormal = Colors.Normal # used a lot
513 col_scheme = self.color_scheme_table.active_scheme_name
542 col_scheme = self.color_scheme_table.active_scheme_name
514 indent = ' '*INDENT_SIZE
543 indent = ' '*INDENT_SIZE
515 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
544 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
516 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
545 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
517 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
546 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
518
547
519 # some internal-use functions
548 # some internal-use functions
520 def text_repr(value):
549 def text_repr(value):
521 """Hopefully pretty robust repr equivalent."""
550 """Hopefully pretty robust repr equivalent."""
522 # this is pretty horrible but should always return *something*
551 # this is pretty horrible but should always return *something*
523 try:
552 try:
524 return pydoc.text.repr(value)
553 return pydoc.text.repr(value)
525 except KeyboardInterrupt:
554 except KeyboardInterrupt:
526 raise
555 raise
527 except:
556 except:
528 try:
557 try:
529 return repr(value)
558 return repr(value)
530 except KeyboardInterrupt:
559 except KeyboardInterrupt:
531 raise
560 raise
532 except:
561 except:
533 try:
562 try:
534 # all still in an except block so we catch
563 # all still in an except block so we catch
535 # getattr raising
564 # getattr raising
536 name = getattr(value, '__name__', None)
565 name = getattr(value, '__name__', None)
537 if name:
566 if name:
538 # ick, recursion
567 # ick, recursion
539 return text_repr(name)
568 return text_repr(name)
540 klass = getattr(value, '__class__', None)
569 klass = getattr(value, '__class__', None)
541 if klass:
570 if klass:
542 return '%s instance' % text_repr(klass)
571 return '%s instance' % text_repr(klass)
543 except KeyboardInterrupt:
572 except KeyboardInterrupt:
544 raise
573 raise
545 except:
574 except:
546 return 'UNRECOVERABLE REPR FAILURE'
575 return 'UNRECOVERABLE REPR FAILURE'
547 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
576 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
548 def nullrepr(value, repr=text_repr): return ''
577 def nullrepr(value, repr=text_repr): return ''
549
578
550 # meat of the code begins
579 # meat of the code begins
551 try:
580 try:
552 etype = etype.__name__
581 etype = etype.__name__
553 except AttributeError:
582 except AttributeError:
554 pass
583 pass
555
584
556 if self.long_header:
585 if self.long_header:
557 # Header with the exception type, python version, and date
586 # Header with the exception type, python version, and date
558 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
587 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
559 date = time.ctime(time.time())
588 date = time.ctime(time.time())
560
589
561 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
590 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
562 exc, ' '*(75-len(str(etype))-len(pyver)),
591 exc, ' '*(75-len(str(etype))-len(pyver)),
563 pyver, string.rjust(date, 75) )
592 pyver, string.rjust(date, 75) )
564 head += "\nA problem occured executing Python code. Here is the sequence of function"\
593 head += "\nA problem occured executing Python code. Here is the sequence of function"\
565 "\ncalls leading up to the error, with the most recent (innermost) call last."
594 "\ncalls leading up to the error, with the most recent (innermost) call last."
566 else:
595 else:
567 # Simplified header
596 # Simplified header
568 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
597 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
569 string.rjust('Traceback (most recent call last)',
598 string.rjust('Traceback (most recent call last)',
570 75 - len(str(etype)) ) )
599 75 - len(str(etype)) ) )
571 frames = []
600 frames = []
572 # Flush cache before calling inspect. This helps alleviate some of the
601 # Flush cache before calling inspect. This helps alleviate some of the
573 # problems with python 2.3's inspect.py.
602 # problems with python 2.3's inspect.py.
574 linecache.checkcache()
603 linecache.checkcache()
575 # Drop topmost frames if requested
604 # Drop topmost frames if requested
576 try:
605 try:
577 # Try the default getinnerframes and Alex's: Alex's fixes some
606 # Try the default getinnerframes and Alex's: Alex's fixes some
578 # problems, but it generates empty tracebacks for console errors
607 # problems, but it generates empty tracebacks for console errors
579 # (5 blanks lines) where none should be returned.
608 # (5 blanks lines) where none should be returned.
580 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
609 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
581 #print 'python records:', records # dbg
610 #print 'python records:', records # dbg
582 records = _fixed_getinnerframes(etb, context,self.tb_offset)
611 records = _fixed_getinnerframes(etb, context,self.tb_offset)
583 #print 'alex records:', records # dbg
612 #print 'alex records:', records # dbg
584 except:
613 except:
585
614
586 # FIXME: I've been getting many crash reports from python 2.3
615 # FIXME: I've been getting many crash reports from python 2.3
587 # users, traceable to inspect.py. If I can find a small test-case
616 # users, traceable to inspect.py. If I can find a small test-case
588 # to reproduce this, I should either write a better workaround or
617 # to reproduce this, I should either write a better workaround or
589 # file a bug report against inspect (if that's the real problem).
618 # file a bug report against inspect (if that's the real problem).
590 # So far, I haven't been able to find an isolated example to
619 # So far, I haven't been able to find an isolated example to
591 # reproduce the problem.
620 # reproduce the problem.
592 inspect_error()
621 inspect_error()
593 traceback.print_exc(file=Term.cerr)
622 traceback.print_exc(file=Term.cerr)
594 info('\nUnfortunately, your original traceback can not be constructed.\n')
623 info('\nUnfortunately, your original traceback can not be constructed.\n')
595 return ''
624 return ''
596
625
597 # build some color string templates outside these nested loops
626 # build some color string templates outside these nested loops
598 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
627 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
599 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
628 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
600 ColorsNormal)
629 ColorsNormal)
601 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
630 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
602 (Colors.vName, Colors.valEm, ColorsNormal)
631 (Colors.vName, Colors.valEm, ColorsNormal)
603 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
632 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
604 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
633 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
605 Colors.vName, ColorsNormal)
634 Colors.vName, ColorsNormal)
606 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
635 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
607 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
636 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
608 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
637 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
609 ColorsNormal)
638 ColorsNormal)
610
639
611 # now, loop over all records printing context and info
640 # now, loop over all records printing context and info
612 abspath = os.path.abspath
641 abspath = os.path.abspath
613 for frame, file, lnum, func, lines, index in records:
642 for frame, file, lnum, func, lines, index in records:
614 #print '*** record:',file,lnum,func,lines,index # dbg
643 #print '*** record:',file,lnum,func,lines,index # dbg
615 try:
644 try:
616 file = file and abspath(file) or '?'
645 file = file and abspath(file) or '?'
617 except OSError:
646 except OSError:
618 # if file is '<console>' or something not in the filesystem,
647 # if file is '<console>' or something not in the filesystem,
619 # the abspath call will throw an OSError. Just ignore it and
648 # the abspath call will throw an OSError. Just ignore it and
620 # keep the original file string.
649 # keep the original file string.
621 pass
650 pass
622 link = tpl_link % file
651 link = tpl_link % file
623 try:
652 try:
624 args, varargs, varkw, locals = inspect.getargvalues(frame)
653 args, varargs, varkw, locals = inspect.getargvalues(frame)
625 except:
654 except:
626 # This can happen due to a bug in python2.3. We should be
655 # This can happen due to a bug in python2.3. We should be
627 # able to remove this try/except when 2.4 becomes a
656 # able to remove this try/except when 2.4 becomes a
628 # requirement. Bug details at http://python.org/sf/1005466
657 # requirement. Bug details at http://python.org/sf/1005466
629 inspect_error()
658 inspect_error()
630 traceback.print_exc(file=Term.cerr)
659 traceback.print_exc(file=Term.cerr)
631 info("\nIPython's exception reporting continues...\n")
660 info("\nIPython's exception reporting continues...\n")
632
661
633 if func == '?':
662 if func == '?':
634 call = ''
663 call = ''
635 else:
664 else:
636 # Decide whether to include variable details or not
665 # Decide whether to include variable details or not
637 var_repr = self.include_vars and eqrepr or nullrepr
666 var_repr = self.include_vars and eqrepr or nullrepr
638 try:
667 try:
639 call = tpl_call % (func,inspect.formatargvalues(args,
668 call = tpl_call % (func,inspect.formatargvalues(args,
640 varargs, varkw,
669 varargs, varkw,
641 locals,formatvalue=var_repr))
670 locals,formatvalue=var_repr))
642 except KeyError:
671 except KeyError:
643 # Very odd crash from inspect.formatargvalues(). The
672 # Very odd crash from inspect.formatargvalues(). The
644 # scenario under which it appeared was a call to
673 # scenario under which it appeared was a call to
645 # view(array,scale) in NumTut.view.view(), where scale had
674 # view(array,scale) in NumTut.view.view(), where scale had
646 # been defined as a scalar (it should be a tuple). Somehow
675 # been defined as a scalar (it should be a tuple). Somehow
647 # inspect messes up resolving the argument list of view()
676 # inspect messes up resolving the argument list of view()
648 # and barfs out. At some point I should dig into this one
677 # and barfs out. At some point I should dig into this one
649 # and file a bug report about it.
678 # and file a bug report about it.
650 inspect_error()
679 inspect_error()
651 traceback.print_exc(file=Term.cerr)
680 traceback.print_exc(file=Term.cerr)
652 info("\nIPython's exception reporting continues...\n")
681 info("\nIPython's exception reporting continues...\n")
653 call = tpl_call_fail % func
682 call = tpl_call_fail % func
654
683
655 # Initialize a list of names on the current line, which the
684 # Initialize a list of names on the current line, which the
656 # tokenizer below will populate.
685 # tokenizer below will populate.
657 names = []
686 names = []
658
687
659 def tokeneater(token_type, token, start, end, line):
688 def tokeneater(token_type, token, start, end, line):
660 """Stateful tokeneater which builds dotted names.
689 """Stateful tokeneater which builds dotted names.
661
690
662 The list of names it appends to (from the enclosing scope) can
691 The list of names it appends to (from the enclosing scope) can
663 contain repeated composite names. This is unavoidable, since
692 contain repeated composite names. This is unavoidable, since
664 there is no way to disambguate partial dotted structures until
693 there is no way to disambguate partial dotted structures until
665 the full list is known. The caller is responsible for pruning
694 the full list is known. The caller is responsible for pruning
666 the final list of duplicates before using it."""
695 the final list of duplicates before using it."""
667
696
668 # build composite names
697 # build composite names
669 if token == '.':
698 if token == '.':
670 try:
699 try:
671 names[-1] += '.'
700 names[-1] += '.'
672 # store state so the next token is added for x.y.z names
701 # store state so the next token is added for x.y.z names
673 tokeneater.name_cont = True
702 tokeneater.name_cont = True
674 return
703 return
675 except IndexError:
704 except IndexError:
676 pass
705 pass
677 if token_type == tokenize.NAME and token not in keyword.kwlist:
706 if token_type == tokenize.NAME and token not in keyword.kwlist:
678 if tokeneater.name_cont:
707 if tokeneater.name_cont:
679 # Dotted names
708 # Dotted names
680 names[-1] += token
709 names[-1] += token
681 tokeneater.name_cont = False
710 tokeneater.name_cont = False
682 else:
711 else:
683 # Regular new names. We append everything, the caller
712 # Regular new names. We append everything, the caller
684 # will be responsible for pruning the list later. It's
713 # will be responsible for pruning the list later. It's
685 # very tricky to try to prune as we go, b/c composite
714 # very tricky to try to prune as we go, b/c composite
686 # names can fool us. The pruning at the end is easy
715 # names can fool us. The pruning at the end is easy
687 # to do (or the caller can print a list with repeated
716 # to do (or the caller can print a list with repeated
688 # names if so desired.
717 # names if so desired.
689 names.append(token)
718 names.append(token)
690 elif token_type == tokenize.NEWLINE:
719 elif token_type == tokenize.NEWLINE:
691 raise IndexError
720 raise IndexError
692 # we need to store a bit of state in the tokenizer to build
721 # we need to store a bit of state in the tokenizer to build
693 # dotted names
722 # dotted names
694 tokeneater.name_cont = False
723 tokeneater.name_cont = False
695
724
696 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
725 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
697 line = getline(file, lnum[0])
726 line = getline(file, lnum[0])
698 lnum[0] += 1
727 lnum[0] += 1
699 return line
728 return line
700
729
701 # Build the list of names on this line of code where the exception
730 # Build the list of names on this line of code where the exception
702 # occurred.
731 # occurred.
703 try:
732 try:
704 # This builds the names list in-place by capturing it from the
733 # This builds the names list in-place by capturing it from the
705 # enclosing scope.
734 # enclosing scope.
706 tokenize.tokenize(linereader, tokeneater)
735 tokenize.tokenize(linereader, tokeneater)
707 except IndexError:
736 except IndexError:
708 # signals exit of tokenizer
737 # signals exit of tokenizer
709 pass
738 pass
710 except tokenize.TokenError,msg:
739 except tokenize.TokenError,msg:
711 _m = ("An unexpected error occurred while tokenizing input\n"
740 _m = ("An unexpected error occurred while tokenizing input\n"
712 "The following traceback may be corrupted or invalid\n"
741 "The following traceback may be corrupted or invalid\n"
713 "The error message is: %s\n" % msg)
742 "The error message is: %s\n" % msg)
714 error(_m)
743 error(_m)
715
744
716 # prune names list of duplicates, but keep the right order
745 # prune names list of duplicates, but keep the right order
717 unique_names = uniq_stable(names)
746 unique_names = uniq_stable(names)
718
747
719 # Start loop over vars
748 # Start loop over vars
720 lvals = []
749 lvals = []
721 if self.include_vars:
750 if self.include_vars:
722 for name_full in unique_names:
751 for name_full in unique_names:
723 name_base = name_full.split('.',1)[0]
752 name_base = name_full.split('.',1)[0]
724 if name_base in frame.f_code.co_varnames:
753 if name_base in frame.f_code.co_varnames:
725 if locals.has_key(name_base):
754 if locals.has_key(name_base):
726 try:
755 try:
727 value = repr(eval(name_full,locals))
756 value = repr(eval(name_full,locals))
728 except:
757 except:
729 value = undefined
758 value = undefined
730 else:
759 else:
731 value = undefined
760 value = undefined
732 name = tpl_local_var % name_full
761 name = tpl_local_var % name_full
733 else:
762 else:
734 if frame.f_globals.has_key(name_base):
763 if frame.f_globals.has_key(name_base):
735 try:
764 try:
736 value = repr(eval(name_full,frame.f_globals))
765 value = repr(eval(name_full,frame.f_globals))
737 except:
766 except:
738 value = undefined
767 value = undefined
739 else:
768 else:
740 value = undefined
769 value = undefined
741 name = tpl_global_var % name_full
770 name = tpl_global_var % name_full
742 lvals.append(tpl_name_val % (name,value))
771 lvals.append(tpl_name_val % (name,value))
743 if lvals:
772 if lvals:
744 lvals = '%s%s' % (indent,em_normal.join(lvals))
773 lvals = '%s%s' % (indent,em_normal.join(lvals))
745 else:
774 else:
746 lvals = ''
775 lvals = ''
747
776
748 level = '%s %s\n' % (link,call)
777 level = '%s %s\n' % (link,call)
749
778
750 if index is None:
779 if index is None:
751 frames.append(level)
780 frames.append(level)
752 else:
781 else:
753 frames.append('%s%s' % (level,''.join(
782 frames.append('%s%s' % (level,''.join(
754 _formatTracebackLines(lnum,index,lines,Colors,lvals,
783 _formatTracebackLines(lnum,index,lines,Colors,lvals,
755 col_scheme))))
784 col_scheme))))
756
785
757 # Get (safely) a string form of the exception info
786 # Get (safely) a string form of the exception info
758 try:
787 try:
759 etype_str,evalue_str = map(str,(etype,evalue))
788 etype_str,evalue_str = map(str,(etype,evalue))
760 except:
789 except:
761 # User exception is improperly defined.
790 # User exception is improperly defined.
762 etype,evalue = str,sys.exc_info()[:2]
791 etype,evalue = str,sys.exc_info()[:2]
763 etype_str,evalue_str = map(str,(etype,evalue))
792 etype_str,evalue_str = map(str,(etype,evalue))
764 # ... and format it
793 # ... and format it
765 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
794 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
766 ColorsNormal, evalue_str)]
795 ColorsNormal, evalue_str)]
767 if type(evalue) is types.InstanceType:
796 if type(evalue) is types.InstanceType:
768 try:
797 try:
769 names = [w for w in dir(evalue) if isinstance(w, basestring)]
798 names = [w for w in dir(evalue) if isinstance(w, basestring)]
770 except:
799 except:
771 # Every now and then, an object with funny inernals blows up
800 # Every now and then, an object with funny inernals blows up
772 # when dir() is called on it. We do the best we can to report
801 # when dir() is called on it. We do the best we can to report
773 # the problem and continue
802 # the problem and continue
774 _m = '%sException reporting error (object with broken dir())%s:'
803 _m = '%sException reporting error (object with broken dir())%s:'
775 exception.append(_m % (Colors.excName,ColorsNormal))
804 exception.append(_m % (Colors.excName,ColorsNormal))
776 etype_str,evalue_str = map(str,sys.exc_info()[:2])
805 etype_str,evalue_str = map(str,sys.exc_info()[:2])
777 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
806 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
778 ColorsNormal, evalue_str))
807 ColorsNormal, evalue_str))
779 names = []
808 names = []
780 for name in names:
809 for name in names:
781 value = text_repr(getattr(evalue, name))
810 value = text_repr(getattr(evalue, name))
782 exception.append('\n%s%s = %s' % (indent, name, value))
811 exception.append('\n%s%s = %s' % (indent, name, value))
812
813 # vds: >>
814 if records:
815 filepath, lnum = records[-1][1:3]
816 #print "file:", str(file), "linenb", str(lnum) # dbg
817 filepath = os.path.abspath(filepath)
818 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
819 # vds: <<
820
783 # return all our info assembled as a single string
821 # return all our info assembled as a single string
784 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
822 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
785
823
786 def debugger(self,force=False):
824 def debugger(self,force=False):
787 """Call up the pdb debugger if desired, always clean up the tb
825 """Call up the pdb debugger if desired, always clean up the tb
788 reference.
826 reference.
789
827
790 Keywords:
828 Keywords:
791
829
792 - force(False): by default, this routine checks the instance call_pdb
830 - force(False): by default, this routine checks the instance call_pdb
793 flag and does not actually invoke the debugger if the flag is false.
831 flag and does not actually invoke the debugger if the flag is false.
794 The 'force' option forces the debugger to activate even if the flag
832 The 'force' option forces the debugger to activate even if the flag
795 is false.
833 is false.
796
834
797 If the call_pdb flag is set, the pdb interactive debugger is
835 If the call_pdb flag is set, the pdb interactive debugger is
798 invoked. In all cases, the self.tb reference to the current traceback
836 invoked. In all cases, the self.tb reference to the current traceback
799 is deleted to prevent lingering references which hamper memory
837 is deleted to prevent lingering references which hamper memory
800 management.
838 management.
801
839
802 Note that each call to pdb() does an 'import readline', so if your app
840 Note that each call to pdb() does an 'import readline', so if your app
803 requires a special setup for the readline completers, you'll have to
841 requires a special setup for the readline completers, you'll have to
804 fix that by hand after invoking the exception handler."""
842 fix that by hand after invoking the exception handler."""
805
843
806 if force or self.call_pdb:
844 if force or self.call_pdb:
807 if self.pdb is None:
845 if self.pdb is None:
808 self.pdb = Debugger.Pdb(
846 self.pdb = Debugger.Pdb(
809 self.color_scheme_table.active_scheme_name)
847 self.color_scheme_table.active_scheme_name)
810 # the system displayhook may have changed, restore the original
848 # the system displayhook may have changed, restore the original
811 # for pdb
849 # for pdb
812 dhook = sys.displayhook
850 dhook = sys.displayhook
813 sys.displayhook = sys.__displayhook__
851 sys.displayhook = sys.__displayhook__
814 self.pdb.reset()
852 self.pdb.reset()
815 # Find the right frame so we don't pop up inside ipython itself
853 # Find the right frame so we don't pop up inside ipython itself
816 if hasattr(self,'tb'):
854 if hasattr(self,'tb'):
817 etb = self.tb
855 etb = self.tb
818 else:
856 else:
819 etb = self.tb = sys.last_traceback
857 etb = self.tb = sys.last_traceback
820 while self.tb.tb_next is not None:
858 while self.tb.tb_next is not None:
821 self.tb = self.tb.tb_next
859 self.tb = self.tb.tb_next
822 try:
860 try:
823 if etb and etb.tb_next:
861 if etb and etb.tb_next:
824 etb = etb.tb_next
862 etb = etb.tb_next
825 self.pdb.botframe = etb.tb_frame
863 self.pdb.botframe = etb.tb_frame
826 self.pdb.interaction(self.tb.tb_frame, self.tb)
864 self.pdb.interaction(self.tb.tb_frame, self.tb)
827 finally:
865 finally:
828 sys.displayhook = dhook
866 sys.displayhook = dhook
829
867
830 if hasattr(self,'tb'):
868 if hasattr(self,'tb'):
831 del self.tb
869 del self.tb
832
870
833 def handler(self, info=None):
871 def handler(self, info=None):
834 (etype, evalue, etb) = info or sys.exc_info()
872 (etype, evalue, etb) = info or sys.exc_info()
835 self.tb = etb
873 self.tb = etb
836 Term.cout.flush()
874 Term.cout.flush()
837 Term.cerr.flush()
838 print >> Term.cerr, self.text(etype, evalue, etb)
875 print >> Term.cerr, self.text(etype, evalue, etb)
876 Term.cerr.flush()
839
877
840 # Changed so an instance can just be called as VerboseTB_inst() and print
878 # Changed so an instance can just be called as VerboseTB_inst() and print
841 # out the right info on its own.
879 # out the right info on its own.
842 def __call__(self, etype=None, evalue=None, etb=None):
880 def __call__(self, etype=None, evalue=None, etb=None):
843 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
844 if etb is None:
882 if etb is None:
845 self.handler()
883 self.handler()
846 else:
884 else:
847 self.handler((etype, evalue, etb))
885 self.handler((etype, evalue, etb))
848 self.debugger()
886 try:
887 self.debugger()
888 except KeyboardInterrupt:
889 print "\nKeyboardInterrupt"
849
890
850 #----------------------------------------------------------------------------
891 #----------------------------------------------------------------------------
851 class FormattedTB(VerboseTB,ListTB):
892 class FormattedTB(VerboseTB,ListTB):
852 """Subclass ListTB but allow calling with a traceback.
893 """Subclass ListTB but allow calling with a traceback.
853
894
854 It can thus be used as a sys.excepthook for Python > 2.1.
895 It can thus be used as a sys.excepthook for Python > 2.1.
855
896
856 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
897 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
857
898
858 Allows a tb_offset to be specified. This is useful for situations where
899 Allows a tb_offset to be specified. This is useful for situations where
859 one needs to remove a number of topmost frames from the traceback (such as
900 one needs to remove a number of topmost frames from the traceback (such as
860 occurs with python programs that themselves execute other python code,
901 occurs with python programs that themselves execute other python code,
861 like Python shells). """
902 like Python shells). """
862
903
863 def __init__(self, mode = 'Plain', color_scheme='Linux',
904 def __init__(self, mode = 'Plain', color_scheme='Linux',
864 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
905 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
865
906
866 # NEVER change the order of this list. Put new modes at the end:
907 # NEVER change the order of this list. Put new modes at the end:
867 self.valid_modes = ['Plain','Context','Verbose']
908 self.valid_modes = ['Plain','Context','Verbose']
868 self.verbose_modes = self.valid_modes[1:3]
909 self.verbose_modes = self.valid_modes[1:3]
869
910
870 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
911 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
871 call_pdb=call_pdb,include_vars=include_vars)
912 call_pdb=call_pdb,include_vars=include_vars)
872 self.set_mode(mode)
913 self.set_mode(mode)
873
914
874 def _extract_tb(self,tb):
915 def _extract_tb(self,tb):
875 if tb:
916 if tb:
876 return traceback.extract_tb(tb)
917 return traceback.extract_tb(tb)
877 else:
918 else:
878 return None
919 return None
879
920
880 def text(self, etype, value, tb,context=5,mode=None):
921 def text(self, etype, value, tb,context=5,mode=None):
881 """Return formatted traceback.
922 """Return formatted traceback.
882
923
883 If the optional mode parameter is given, it overrides the current
924 If the optional mode parameter is given, it overrides the current
884 mode."""
925 mode."""
885
926
886 if mode is None:
927 if mode is None:
887 mode = self.mode
928 mode = self.mode
888 if mode in self.verbose_modes:
929 if mode in self.verbose_modes:
889 # verbose modes need a full traceback
930 # verbose modes need a full traceback
890 return VerboseTB.text(self,etype, value, tb,context=5)
931 return VerboseTB.text(self,etype, value, tb,context=5)
891 else:
932 else:
892 # We must check the source cache because otherwise we can print
933 # We must check the source cache because otherwise we can print
893 # out-of-date source code.
934 # out-of-date source code.
894 linecache.checkcache()
935 linecache.checkcache()
895 # Now we can extract and format the exception
936 # Now we can extract and format the exception
896 elist = self._extract_tb(tb)
937 elist = self._extract_tb(tb)
897 if len(elist) > self.tb_offset:
938 if len(elist) > self.tb_offset:
898 del elist[:self.tb_offset]
939 del elist[:self.tb_offset]
899 return ListTB.text(self,etype,value,elist)
940 return ListTB.text(self,etype,value,elist)
900
941
901 def set_mode(self,mode=None):
942 def set_mode(self,mode=None):
902 """Switch to the desired mode.
943 """Switch to the desired mode.
903
944
904 If mode is not specified, cycles through the available modes."""
945 If mode is not specified, cycles through the available modes."""
905
946
906 if not mode:
947 if not mode:
907 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
948 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
908 len(self.valid_modes)
949 len(self.valid_modes)
909 self.mode = self.valid_modes[new_idx]
950 self.mode = self.valid_modes[new_idx]
910 elif mode not in self.valid_modes:
951 elif mode not in self.valid_modes:
911 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
952 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
912 'Valid modes: '+str(self.valid_modes)
953 'Valid modes: '+str(self.valid_modes)
913 else:
954 else:
914 self.mode = mode
955 self.mode = mode
915 # include variable details only in 'Verbose' mode
956 # include variable details only in 'Verbose' mode
916 self.include_vars = (self.mode == self.valid_modes[2])
957 self.include_vars = (self.mode == self.valid_modes[2])
917
958
918 # some convenient shorcuts
959 # some convenient shorcuts
919 def plain(self):
960 def plain(self):
920 self.set_mode(self.valid_modes[0])
961 self.set_mode(self.valid_modes[0])
921
962
922 def context(self):
963 def context(self):
923 self.set_mode(self.valid_modes[1])
964 self.set_mode(self.valid_modes[1])
924
965
925 def verbose(self):
966 def verbose(self):
926 self.set_mode(self.valid_modes[2])
967 self.set_mode(self.valid_modes[2])
927
968
928 #----------------------------------------------------------------------------
969 #----------------------------------------------------------------------------
929 class AutoFormattedTB(FormattedTB):
970 class AutoFormattedTB(FormattedTB):
930 """A traceback printer which can be called on the fly.
971 """A traceback printer which can be called on the fly.
931
972
932 It will find out about exceptions by itself.
973 It will find out about exceptions by itself.
933
974
934 A brief example:
975 A brief example:
935
976
936 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
977 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
937 try:
978 try:
938 ...
979 ...
939 except:
980 except:
940 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
981 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
941 """
982 """
942 def __call__(self,etype=None,evalue=None,etb=None,
983 def __call__(self,etype=None,evalue=None,etb=None,
943 out=None,tb_offset=None):
984 out=None,tb_offset=None):
944 """Print out a formatted exception traceback.
985 """Print out a formatted exception traceback.
945
986
946 Optional arguments:
987 Optional arguments:
947 - out: an open file-like object to direct output to.
988 - out: an open file-like object to direct output to.
948
989
949 - tb_offset: the number of frames to skip over in the stack, on a
990 - tb_offset: the number of frames to skip over in the stack, on a
950 per-call basis (this overrides temporarily the instance's tb_offset
991 per-call basis (this overrides temporarily the instance's tb_offset
951 given at initialization time. """
992 given at initialization time. """
952
993
953 if out is None:
994 if out is None:
954 out = Term.cerr
995 out = Term.cerr
955 Term.cout.flush()
996 Term.cout.flush()
956 out.flush()
957 if tb_offset is not None:
997 if tb_offset is not None:
958 tb_offset, self.tb_offset = self.tb_offset, tb_offset
998 tb_offset, self.tb_offset = self.tb_offset, tb_offset
959 print >> out, self.text(etype, evalue, etb)
999 print >> out, self.text(etype, evalue, etb)
960 self.tb_offset = tb_offset
1000 self.tb_offset = tb_offset
961 else:
1001 else:
962 print >> out, self.text(etype, evalue, etb)
1002 print >> out, self.text(etype, evalue, etb)
963 self.debugger()
1003 out.flush()
1004 try:
1005 self.debugger()
1006 except KeyboardInterrupt:
1007 print "\nKeyboardInterrupt"
964
1008
965 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1009 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
966 if etype is None:
1010 if etype is None:
967 etype,value,tb = sys.exc_info()
1011 etype,value,tb = sys.exc_info()
968 self.tb = tb
1012 self.tb = tb
969 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1013 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
970
1014
971 #---------------------------------------------------------------------------
1015 #---------------------------------------------------------------------------
972 # A simple class to preserve Nathan's original functionality.
1016 # A simple class to preserve Nathan's original functionality.
973 class ColorTB(FormattedTB):
1017 class ColorTB(FormattedTB):
974 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1018 """Shorthand to initialize a FormattedTB in Linux colors mode."""
975 def __init__(self,color_scheme='Linux',call_pdb=0):
1019 def __init__(self,color_scheme='Linux',call_pdb=0):
976 FormattedTB.__init__(self,color_scheme=color_scheme,
1020 FormattedTB.__init__(self,color_scheme=color_scheme,
977 call_pdb=call_pdb)
1021 call_pdb=call_pdb)
978
1022
979 #----------------------------------------------------------------------------
1023 #----------------------------------------------------------------------------
980 # module testing (minimal)
1024 # module testing (minimal)
981 if __name__ == "__main__":
1025 if __name__ == "__main__":
982 def spam(c, (d, e)):
1026 def spam(c, (d, e)):
983 x = c + d
1027 x = c + d
984 y = c * d
1028 y = c * d
985 foo(x, y)
1029 foo(x, y)
986
1030
987 def foo(a, b, bar=1):
1031 def foo(a, b, bar=1):
988 eggs(a, b + bar)
1032 eggs(a, b + bar)
989
1033
990 def eggs(f, g, z=globals()):
1034 def eggs(f, g, z=globals()):
991 h = f + g
1035 h = f + g
992 i = f - g
1036 i = f - g
993 return h / i
1037 return h / i
994
1038
995 print ''
1039 print ''
996 print '*** Before ***'
1040 print '*** Before ***'
997 try:
1041 try:
998 print spam(1, (2, 3))
1042 print spam(1, (2, 3))
999 except:
1043 except:
1000 traceback.print_exc()
1044 traceback.print_exc()
1001 print ''
1045 print ''
1002
1046
1003 handler = ColorTB()
1047 handler = ColorTB()
1004 print '*** ColorTB ***'
1048 print '*** ColorTB ***'
1005 try:
1049 try:
1006 print spam(1, (2, 3))
1050 print spam(1, (2, 3))
1007 except:
1051 except:
1008 apply(handler, sys.exc_info() )
1052 apply(handler, sys.exc_info() )
1009 print ''
1053 print ''
1010
1054
1011 handler = VerboseTB()
1055 handler = VerboseTB()
1012 print '*** VerboseTB ***'
1056 print '*** VerboseTB ***'
1013 try:
1057 try:
1014 print spam(1, (2, 3))
1058 print spam(1, (2, 3))
1015 except:
1059 except:
1016 apply(handler, sys.exc_info() )
1060 apply(handler, sys.exc_info() )
1017 print ''
1061 print ''
1018
1062
@@ -1,1062 +1,1062 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultraTB.py -- Spice up your tracebacks!
3 ultraTB.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultraTB
12 import sys,ultraTB
13 sys.excepthook = ultraTB.ColorTB()
13 sys.excepthook = ultraTB.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultraTB
40 import sys,ultraTB
41 sys.excepthook = ultraTB.VerboseTB()
41 sys.excepthook = ultraTB.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
62
63 $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 exception_colors
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 = exception_colors()
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 have_filedata = False
449 have_filedata = False
450 Colors = self.Colors
450 Colors = self.Colors
451 list = []
451 list = []
452 try:
452 try:
453 stype = Colors.excName + etype.__name__ + Colors.Normal
453 stype = Colors.excName + etype.__name__ + Colors.Normal
454 except AttributeError:
454 except AttributeError:
455 stype = etype # String exceptions don't get special coloring
455 stype = etype # String exceptions don't get special coloring
456 if value is None:
456 if value is None:
457 list.append( str(stype) + '\n')
457 list.append( str(stype) + '\n')
458 else:
458 else:
459 if etype is SyntaxError:
459 if etype is SyntaxError:
460 try:
460 try:
461 msg, (filename, lineno, offset, line) = value
461 msg, (filename, lineno, offset, line) = value
462 except:
462 except:
463 have_filedata = False
463 have_filedata = False
464 else:
464 else:
465 have_filedata = True
465 have_filedata = True
466 #print 'filename is',filename # dbg
466 #print 'filename is',filename # dbg
467 if not filename: filename = "<string>"
467 if not filename: filename = "<string>"
468 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
469 (Colors.normalEm,
469 (Colors.normalEm,
470 Colors.filenameEm, filename, Colors.normalEm,
470 Colors.filenameEm, filename, Colors.normalEm,
471 Colors.linenoEm, lineno, Colors.Normal ))
471 Colors.linenoEm, lineno, Colors.Normal ))
472 if line is not None:
472 if line is not None:
473 i = 0
473 i = 0
474 while i < len(line) and line[i].isspace():
474 while i < len(line) and line[i].isspace():
475 i = i+1
475 i = i+1
476 list.append('%s %s%s\n' % (Colors.line,
476 list.append('%s %s%s\n' % (Colors.line,
477 line.strip(),
477 line.strip(),
478 Colors.Normal))
478 Colors.Normal))
479 if offset is not None:
479 if offset is not None:
480 s = ' '
480 s = ' '
481 for c in line[i:offset-1]:
481 for c in line[i:offset-1]:
482 if c.isspace():
482 if c.isspace():
483 s = s + c
483 s = s + c
484 else:
484 else:
485 s = s + ' '
485 s = s + ' '
486 list.append('%s%s^%s\n' % (Colors.caret, s,
486 list.append('%s%s^%s\n' % (Colors.caret, s,
487 Colors.Normal) )
487 Colors.Normal) )
488 value = msg
488 value = msg
489 s = self._some_str(value)
489 s = self._some_str(value)
490 if s:
490 if s:
491 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
491 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
492 Colors.Normal, s))
492 Colors.Normal, s))
493 else:
493 else:
494 list.append('%s\n' % str(stype))
494 list.append('%s\n' % str(stype))
495
495
496 # vds:>>
496 # vds:>>
497 if have_filedata:
497 if have_filedata:
498 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
498 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
499 # vds:<<
499 # vds:<<
500
500
501 return list
501 return list
502
502
503 def _some_str(self, value):
503 def _some_str(self, value):
504 # Lifted from traceback.py
504 # Lifted from traceback.py
505 try:
505 try:
506 return str(value)
506 return str(value)
507 except:
507 except:
508 return '<unprintable %s object>' % type(value).__name__
508 return '<unprintable %s object>' % type(value).__name__
509
509
510 #----------------------------------------------------------------------------
510 #----------------------------------------------------------------------------
511 class VerboseTB(TBTools):
511 class VerboseTB(TBTools):
512 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
512 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
513 of HTML. Requires inspect and pydoc. Crazy, man.
513 of HTML. Requires inspect and pydoc. Crazy, man.
514
514
515 Modified version which optionally strips the topmost entries from the
515 Modified version which optionally strips the topmost entries from the
516 traceback, to be used with alternate interpreters (because their own code
516 traceback, to be used with alternate interpreters (because their own code
517 would appear in the traceback)."""
517 would appear in the traceback)."""
518
518
519 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
519 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
520 call_pdb = 0, include_vars=1):
520 call_pdb = 0, include_vars=1):
521 """Specify traceback offset, headers and color scheme.
521 """Specify traceback offset, headers and color scheme.
522
522
523 Define how many frames to drop from the tracebacks. Calling it with
523 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
524 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
525 their own code at the top of the traceback (VerboseTB will first
526 remove that frame before printing the traceback info)."""
526 remove that frame before printing the traceback info)."""
527 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
527 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
528 self.tb_offset = tb_offset
528 self.tb_offset = tb_offset
529 self.long_header = long_header
529 self.long_header = long_header
530 self.include_vars = include_vars
530 self.include_vars = include_vars
531
531
532 def text(self, etype, evalue, etb, context=5):
532 def text(self, etype, evalue, etb, context=5):
533 """Return a nice text document describing the traceback."""
533 """Return a nice text document describing the traceback."""
534
534
535 # some locals
535 # some locals
536 try:
536 try:
537 etype = etype.__name__
537 etype = etype.__name__
538 except AttributeError:
538 except AttributeError:
539 pass
539 pass
540 Colors = self.Colors # just a shorthand + quicker name lookup
540 Colors = self.Colors # just a shorthand + quicker name lookup
541 ColorsNormal = Colors.Normal # used a lot
541 ColorsNormal = Colors.Normal # used a lot
542 col_scheme = self.color_scheme_table.active_scheme_name
542 col_scheme = self.color_scheme_table.active_scheme_name
543 indent = ' '*INDENT_SIZE
543 indent = ' '*INDENT_SIZE
544 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
544 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
545 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
545 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
546 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
546 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
547
547
548 # some internal-use functions
548 # some internal-use functions
549 def text_repr(value):
549 def text_repr(value):
550 """Hopefully pretty robust repr equivalent."""
550 """Hopefully pretty robust repr equivalent."""
551 # this is pretty horrible but should always return *something*
551 # this is pretty horrible but should always return *something*
552 try:
552 try:
553 return pydoc.text.repr(value)
553 return pydoc.text.repr(value)
554 except KeyboardInterrupt:
554 except KeyboardInterrupt:
555 raise
555 raise
556 except:
556 except:
557 try:
557 try:
558 return repr(value)
558 return repr(value)
559 except KeyboardInterrupt:
559 except KeyboardInterrupt:
560 raise
560 raise
561 except:
561 except:
562 try:
562 try:
563 # all still in an except block so we catch
563 # all still in an except block so we catch
564 # getattr raising
564 # getattr raising
565 name = getattr(value, '__name__', None)
565 name = getattr(value, '__name__', None)
566 if name:
566 if name:
567 # ick, recursion
567 # ick, recursion
568 return text_repr(name)
568 return text_repr(name)
569 klass = getattr(value, '__class__', None)
569 klass = getattr(value, '__class__', None)
570 if klass:
570 if klass:
571 return '%s instance' % text_repr(klass)
571 return '%s instance' % text_repr(klass)
572 except KeyboardInterrupt:
572 except KeyboardInterrupt:
573 raise
573 raise
574 except:
574 except:
575 return 'UNRECOVERABLE REPR FAILURE'
575 return 'UNRECOVERABLE REPR FAILURE'
576 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
576 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
577 def nullrepr(value, repr=text_repr): return ''
577 def nullrepr(value, repr=text_repr): return ''
578
578
579 # meat of the code begins
579 # meat of the code begins
580 try:
580 try:
581 etype = etype.__name__
581 etype = etype.__name__
582 except AttributeError:
582 except AttributeError:
583 pass
583 pass
584
584
585 if self.long_header:
585 if self.long_header:
586 # Header with the exception type, python version, and date
586 # Header with the exception type, python version, and date
587 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
587 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
588 date = time.ctime(time.time())
588 date = time.ctime(time.time())
589
589
590 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
590 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
591 exc, ' '*(75-len(str(etype))-len(pyver)),
591 exc, ' '*(75-len(str(etype))-len(pyver)),
592 pyver, string.rjust(date, 75) )
592 pyver, string.rjust(date, 75) )
593 head += "\nA problem occured executing Python code. Here is the sequence of function"\
593 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."
594 "\ncalls leading up to the error, with the most recent (innermost) call last."
595 else:
595 else:
596 # Simplified header
596 # Simplified header
597 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
597 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
598 string.rjust('Traceback (most recent call last)',
598 string.rjust('Traceback (most recent call last)',
599 75 - len(str(etype)) ) )
599 75 - len(str(etype)) ) )
600 frames = []
600 frames = []
601 # Flush cache before calling inspect. This helps alleviate some of the
601 # Flush cache before calling inspect. This helps alleviate some of the
602 # problems with python 2.3's inspect.py.
602 # problems with python 2.3's inspect.py.
603 linecache.checkcache()
603 linecache.checkcache()
604 # Drop topmost frames if requested
604 # Drop topmost frames if requested
605 try:
605 try:
606 # Try the default getinnerframes and Alex's: Alex's fixes some
606 # Try the default getinnerframes and Alex's: Alex's fixes some
607 # problems, but it generates empty tracebacks for console errors
607 # problems, but it generates empty tracebacks for console errors
608 # (5 blanks lines) where none should be returned.
608 # (5 blanks lines) where none should be returned.
609 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
609 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
610 #print 'python records:', records # dbg
610 #print 'python records:', records # dbg
611 records = _fixed_getinnerframes(etb, context,self.tb_offset)
611 records = _fixed_getinnerframes(etb, context,self.tb_offset)
612 #print 'alex records:', records # dbg
612 #print 'alex records:', records # dbg
613 except:
613 except:
614
614
615 # FIXME: I've been getting many crash reports from python 2.3
615 # 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
616 # 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
617 # to reproduce this, I should either write a better workaround or
618 # file a bug report against inspect (if that's the real problem).
618 # 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
619 # So far, I haven't been able to find an isolated example to
620 # reproduce the problem.
620 # reproduce the problem.
621 inspect_error()
621 inspect_error()
622 traceback.print_exc(file=Term.cerr)
622 traceback.print_exc(file=Term.cerr)
623 info('\nUnfortunately, your original traceback can not be constructed.\n')
623 info('\nUnfortunately, your original traceback can not be constructed.\n')
624 return ''
624 return ''
625
625
626 # build some color string templates outside these nested loops
626 # build some color string templates outside these nested loops
627 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
627 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
628 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
628 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
629 ColorsNormal)
629 ColorsNormal)
630 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
630 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
631 (Colors.vName, Colors.valEm, ColorsNormal)
631 (Colors.vName, Colors.valEm, ColorsNormal)
632 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
632 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
633 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
633 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
634 Colors.vName, ColorsNormal)
634 Colors.vName, ColorsNormal)
635 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
635 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
636 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
636 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
637 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
637 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
638 ColorsNormal)
638 ColorsNormal)
639
639
640 # now, loop over all records printing context and info
640 # now, loop over all records printing context and info
641 abspath = os.path.abspath
641 abspath = os.path.abspath
642 for frame, file, lnum, func, lines, index in records:
642 for frame, file, lnum, func, lines, index in records:
643 #print '*** record:',file,lnum,func,lines,index # dbg
643 #print '*** record:',file,lnum,func,lines,index # dbg
644 try:
644 try:
645 file = file and abspath(file) or '?'
645 file = file and abspath(file) or '?'
646 except OSError:
646 except OSError:
647 # if file is '<console>' or something not in the filesystem,
647 # if file is '<console>' or something not in the filesystem,
648 # the abspath call will throw an OSError. Just ignore it and
648 # the abspath call will throw an OSError. Just ignore it and
649 # keep the original file string.
649 # keep the original file string.
650 pass
650 pass
651 link = tpl_link % file
651 link = tpl_link % file
652 try:
652 try:
653 args, varargs, varkw, locals = inspect.getargvalues(frame)
653 args, varargs, varkw, locals = inspect.getargvalues(frame)
654 except:
654 except:
655 # This can happen due to a bug in python2.3. We should be
655 # 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
656 # able to remove this try/except when 2.4 becomes a
657 # requirement. Bug details at http://python.org/sf/1005466
657 # requirement. Bug details at http://python.org/sf/1005466
658 inspect_error()
658 inspect_error()
659 traceback.print_exc(file=Term.cerr)
659 traceback.print_exc(file=Term.cerr)
660 info("\nIPython's exception reporting continues...\n")
660 info("\nIPython's exception reporting continues...\n")
661
661
662 if func == '?':
662 if func == '?':
663 call = ''
663 call = ''
664 else:
664 else:
665 # Decide whether to include variable details or not
665 # Decide whether to include variable details or not
666 var_repr = self.include_vars and eqrepr or nullrepr
666 var_repr = self.include_vars and eqrepr or nullrepr
667 try:
667 try:
668 call = tpl_call % (func,inspect.formatargvalues(args,
668 call = tpl_call % (func,inspect.formatargvalues(args,
669 varargs, varkw,
669 varargs, varkw,
670 locals,formatvalue=var_repr))
670 locals,formatvalue=var_repr))
671 except KeyError:
671 except KeyError:
672 # Very odd crash from inspect.formatargvalues(). The
672 # Very odd crash from inspect.formatargvalues(). The
673 # scenario under which it appeared was a call to
673 # scenario under which it appeared was a call to
674 # view(array,scale) in NumTut.view.view(), where scale had
674 # view(array,scale) in NumTut.view.view(), where scale had
675 # been defined as a scalar (it should be a tuple). Somehow
675 # been defined as a scalar (it should be a tuple). Somehow
676 # inspect messes up resolving the argument list of view()
676 # inspect messes up resolving the argument list of view()
677 # and barfs out. At some point I should dig into this one
677 # and barfs out. At some point I should dig into this one
678 # and file a bug report about it.
678 # and file a bug report about it.
679 inspect_error()
679 inspect_error()
680 traceback.print_exc(file=Term.cerr)
680 traceback.print_exc(file=Term.cerr)
681 info("\nIPython's exception reporting continues...\n")
681 info("\nIPython's exception reporting continues...\n")
682 call = tpl_call_fail % func
682 call = tpl_call_fail % func
683
683
684 # Initialize a list of names on the current line, which the
684 # Initialize a list of names on the current line, which the
685 # tokenizer below will populate.
685 # tokenizer below will populate.
686 names = []
686 names = []
687
687
688 def tokeneater(token_type, token, start, end, line):
688 def tokeneater(token_type, token, start, end, line):
689 """Stateful tokeneater which builds dotted names.
689 """Stateful tokeneater which builds dotted names.
690
690
691 The list of names it appends to (from the enclosing scope) can
691 The list of names it appends to (from the enclosing scope) can
692 contain repeated composite names. This is unavoidable, since
692 contain repeated composite names. This is unavoidable, since
693 there is no way to disambguate partial dotted structures until
693 there is no way to disambguate partial dotted structures until
694 the full list is known. The caller is responsible for pruning
694 the full list is known. The caller is responsible for pruning
695 the final list of duplicates before using it."""
695 the final list of duplicates before using it."""
696
696
697 # build composite names
697 # build composite names
698 if token == '.':
698 if token == '.':
699 try:
699 try:
700 names[-1] += '.'
700 names[-1] += '.'
701 # store state so the next token is added for x.y.z names
701 # store state so the next token is added for x.y.z names
702 tokeneater.name_cont = True
702 tokeneater.name_cont = True
703 return
703 return
704 except IndexError:
704 except IndexError:
705 pass
705 pass
706 if token_type == tokenize.NAME and token not in keyword.kwlist:
706 if token_type == tokenize.NAME and token not in keyword.kwlist:
707 if tokeneater.name_cont:
707 if tokeneater.name_cont:
708 # Dotted names
708 # Dotted names
709 names[-1] += token
709 names[-1] += token
710 tokeneater.name_cont = False
710 tokeneater.name_cont = False
711 else:
711 else:
712 # Regular new names. We append everything, the caller
712 # Regular new names. We append everything, the caller
713 # will be responsible for pruning the list later. It's
713 # will be responsible for pruning the list later. It's
714 # very tricky to try to prune as we go, b/c composite
714 # very tricky to try to prune as we go, b/c composite
715 # names can fool us. The pruning at the end is easy
715 # names can fool us. The pruning at the end is easy
716 # to do (or the caller can print a list with repeated
716 # to do (or the caller can print a list with repeated
717 # names if so desired.
717 # names if so desired.
718 names.append(token)
718 names.append(token)
719 elif token_type == tokenize.NEWLINE:
719 elif token_type == tokenize.NEWLINE:
720 raise IndexError
720 raise IndexError
721 # we need to store a bit of state in the tokenizer to build
721 # we need to store a bit of state in the tokenizer to build
722 # dotted names
722 # dotted names
723 tokeneater.name_cont = False
723 tokeneater.name_cont = False
724
724
725 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
725 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
726 line = getline(file, lnum[0])
726 line = getline(file, lnum[0])
727 lnum[0] += 1
727 lnum[0] += 1
728 return line
728 return line
729
729
730 # Build the list of names on this line of code where the exception
730 # Build the list of names on this line of code where the exception
731 # occurred.
731 # occurred.
732 try:
732 try:
733 # This builds the names list in-place by capturing it from the
733 # This builds the names list in-place by capturing it from the
734 # enclosing scope.
734 # enclosing scope.
735 tokenize.tokenize(linereader, tokeneater)
735 tokenize.tokenize(linereader, tokeneater)
736 except IndexError:
736 except IndexError:
737 # signals exit of tokenizer
737 # signals exit of tokenizer
738 pass
738 pass
739 except tokenize.TokenError,msg:
739 except tokenize.TokenError,msg:
740 _m = ("An unexpected error occurred while tokenizing input\n"
740 _m = ("An unexpected error occurred while tokenizing input\n"
741 "The following traceback may be corrupted or invalid\n"
741 "The following traceback may be corrupted or invalid\n"
742 "The error message is: %s\n" % msg)
742 "The error message is: %s\n" % msg)
743 error(_m)
743 error(_m)
744
744
745 # prune names list of duplicates, but keep the right order
745 # prune names list of duplicates, but keep the right order
746 unique_names = uniq_stable(names)
746 unique_names = uniq_stable(names)
747
747
748 # Start loop over vars
748 # Start loop over vars
749 lvals = []
749 lvals = []
750 if self.include_vars:
750 if self.include_vars:
751 for name_full in unique_names:
751 for name_full in unique_names:
752 name_base = name_full.split('.',1)[0]
752 name_base = name_full.split('.',1)[0]
753 if name_base in frame.f_code.co_varnames:
753 if name_base in frame.f_code.co_varnames:
754 if locals.has_key(name_base):
754 if locals.has_key(name_base):
755 try:
755 try:
756 value = repr(eval(name_full,locals))
756 value = repr(eval(name_full,locals))
757 except:
757 except:
758 value = undefined
758 value = undefined
759 else:
759 else:
760 value = undefined
760 value = undefined
761 name = tpl_local_var % name_full
761 name = tpl_local_var % name_full
762 else:
762 else:
763 if frame.f_globals.has_key(name_base):
763 if frame.f_globals.has_key(name_base):
764 try:
764 try:
765 value = repr(eval(name_full,frame.f_globals))
765 value = repr(eval(name_full,frame.f_globals))
766 except:
766 except:
767 value = undefined
767 value = undefined
768 else:
768 else:
769 value = undefined
769 value = undefined
770 name = tpl_global_var % name_full
770 name = tpl_global_var % name_full
771 lvals.append(tpl_name_val % (name,value))
771 lvals.append(tpl_name_val % (name,value))
772 if lvals:
772 if lvals:
773 lvals = '%s%s' % (indent,em_normal.join(lvals))
773 lvals = '%s%s' % (indent,em_normal.join(lvals))
774 else:
774 else:
775 lvals = ''
775 lvals = ''
776
776
777 level = '%s %s\n' % (link,call)
777 level = '%s %s\n' % (link,call)
778
778
779 if index is None:
779 if index is None:
780 frames.append(level)
780 frames.append(level)
781 else:
781 else:
782 frames.append('%s%s' % (level,''.join(
782 frames.append('%s%s' % (level,''.join(
783 _formatTracebackLines(lnum,index,lines,Colors,lvals,
783 _formatTracebackLines(lnum,index,lines,Colors,lvals,
784 col_scheme))))
784 col_scheme))))
785
785
786 # Get (safely) a string form of the exception info
786 # Get (safely) a string form of the exception info
787 try:
787 try:
788 etype_str,evalue_str = map(str,(etype,evalue))
788 etype_str,evalue_str = map(str,(etype,evalue))
789 except:
789 except:
790 # User exception is improperly defined.
790 # User exception is improperly defined.
791 etype,evalue = str,sys.exc_info()[:2]
791 etype,evalue = str,sys.exc_info()[:2]
792 etype_str,evalue_str = map(str,(etype,evalue))
792 etype_str,evalue_str = map(str,(etype,evalue))
793 # ... and format it
793 # ... and format it
794 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
794 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
795 ColorsNormal, evalue_str)]
795 ColorsNormal, evalue_str)]
796 if type(evalue) is types.InstanceType:
796 if type(evalue) is types.InstanceType:
797 try:
797 try:
798 names = [w for w in dir(evalue) if isinstance(w, basestring)]
798 names = [w for w in dir(evalue) if isinstance(w, basestring)]
799 except:
799 except:
800 # Every now and then, an object with funny inernals blows up
800 # 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
801 # when dir() is called on it. We do the best we can to report
802 # the problem and continue
802 # the problem and continue
803 _m = '%sException reporting error (object with broken dir())%s:'
803 _m = '%sException reporting error (object with broken dir())%s:'
804 exception.append(_m % (Colors.excName,ColorsNormal))
804 exception.append(_m % (Colors.excName,ColorsNormal))
805 etype_str,evalue_str = map(str,sys.exc_info()[:2])
805 etype_str,evalue_str = map(str,sys.exc_info()[:2])
806 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
806 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
807 ColorsNormal, evalue_str))
807 ColorsNormal, evalue_str))
808 names = []
808 names = []
809 for name in names:
809 for name in names:
810 value = text_repr(getattr(evalue, name))
810 value = text_repr(getattr(evalue, name))
811 exception.append('\n%s%s = %s' % (indent, name, value))
811 exception.append('\n%s%s = %s' % (indent, name, value))
812
812
813 # vds: >>
813 # vds: >>
814 if records:
814 if records:
815 filepath, lnum = records[-1][1:3]
815 filepath, lnum = records[-1][1:3]
816 #print "file:", str(file), "linenb", str(lnum) # dbg
816 #print "file:", str(file), "linenb", str(lnum) # dbg
817 filepath = os.path.abspath(filepath)
817 filepath = os.path.abspath(filepath)
818 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
818 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
819 # vds: <<
819 # vds: <<
820
820
821 # return all our info assembled as a single string
821 # return all our info assembled as a single string
822 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
822 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
823
823
824 def debugger(self,force=False):
824 def debugger(self,force=False):
825 """Call up the pdb debugger if desired, always clean up the tb
825 """Call up the pdb debugger if desired, always clean up the tb
826 reference.
826 reference.
827
827
828 Keywords:
828 Keywords:
829
829
830 - force(False): by default, this routine checks the instance call_pdb
830 - force(False): by default, this routine checks the instance call_pdb
831 flag and does not actually invoke the debugger if the flag is false.
831 flag and does not actually invoke the debugger if the flag is false.
832 The 'force' option forces the debugger to activate even if the flag
832 The 'force' option forces the debugger to activate even if the flag
833 is false.
833 is false.
834
834
835 If the call_pdb flag is set, the pdb interactive debugger is
835 If the call_pdb flag is set, the pdb interactive debugger is
836 invoked. In all cases, the self.tb reference to the current traceback
836 invoked. In all cases, the self.tb reference to the current traceback
837 is deleted to prevent lingering references which hamper memory
837 is deleted to prevent lingering references which hamper memory
838 management.
838 management.
839
839
840 Note that each call to pdb() does an 'import readline', so if your app
840 Note that each call to pdb() does an 'import readline', so if your app
841 requires a special setup for the readline completers, you'll have to
841 requires a special setup for the readline completers, you'll have to
842 fix that by hand after invoking the exception handler."""
842 fix that by hand after invoking the exception handler."""
843
843
844 if force or self.call_pdb:
844 if force or self.call_pdb:
845 if self.pdb is None:
845 if self.pdb is None:
846 self.pdb = Debugger.Pdb(
846 self.pdb = Debugger.Pdb(
847 self.color_scheme_table.active_scheme_name)
847 self.color_scheme_table.active_scheme_name)
848 # the system displayhook may have changed, restore the original
848 # the system displayhook may have changed, restore the original
849 # for pdb
849 # for pdb
850 dhook = sys.displayhook
850 dhook = sys.displayhook
851 sys.displayhook = sys.__displayhook__
851 sys.displayhook = sys.__displayhook__
852 self.pdb.reset()
852 self.pdb.reset()
853 # Find the right frame so we don't pop up inside ipython itself
853 # Find the right frame so we don't pop up inside ipython itself
854 if hasattr(self,'tb'):
854 if hasattr(self,'tb'):
855 etb = self.tb
855 etb = self.tb
856 else:
856 else:
857 etb = self.tb = sys.last_traceback
857 etb = self.tb = sys.last_traceback
858 while self.tb.tb_next is not None:
858 while self.tb.tb_next is not None:
859 self.tb = self.tb.tb_next
859 self.tb = self.tb.tb_next
860 try:
860 try:
861 if etb and etb.tb_next:
861 if etb and etb.tb_next:
862 etb = etb.tb_next
862 etb = etb.tb_next
863 self.pdb.botframe = etb.tb_frame
863 self.pdb.botframe = etb.tb_frame
864 self.pdb.interaction(self.tb.tb_frame, self.tb)
864 self.pdb.interaction(self.tb.tb_frame, self.tb)
865 finally:
865 finally:
866 sys.displayhook = dhook
866 sys.displayhook = dhook
867
867
868 if hasattr(self,'tb'):
868 if hasattr(self,'tb'):
869 del self.tb
869 del self.tb
870
870
871 def handler(self, info=None):
871 def handler(self, info=None):
872 (etype, evalue, etb) = info or sys.exc_info()
872 (etype, evalue, etb) = info or sys.exc_info()
873 self.tb = etb
873 self.tb = etb
874 Term.cout.flush()
874 Term.cout.flush()
875 print >> Term.cerr, self.text(etype, evalue, etb)
875 print >> Term.cerr, self.text(etype, evalue, etb)
876 Term.cerr.flush()
876 Term.cerr.flush()
877
877
878 # Changed so an instance can just be called as VerboseTB_inst() and print
878 # Changed so an instance can just be called as VerboseTB_inst() and print
879 # out the right info on its own.
879 # out the right info on its own.
880 def __call__(self, etype=None, evalue=None, etb=None):
880 def __call__(self, etype=None, evalue=None, etb=None):
881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
882 if etb is None:
882 if etb is None:
883 self.handler()
883 self.handler()
884 else:
884 else:
885 self.handler((etype, evalue, etb))
885 self.handler((etype, evalue, etb))
886 try:
886 try:
887 self.debugger()
887 self.debugger()
888 except KeyboardInterrupt:
888 except KeyboardInterrupt:
889 print "\nKeyboardInterrupt"
889 print "\nKeyboardInterrupt"
890
890
891 #----------------------------------------------------------------------------
891 #----------------------------------------------------------------------------
892 class FormattedTB(VerboseTB,ListTB):
892 class FormattedTB(VerboseTB,ListTB):
893 """Subclass ListTB but allow calling with a traceback.
893 """Subclass ListTB but allow calling with a traceback.
894
894
895 It can thus be used as a sys.excepthook for Python > 2.1.
895 It can thus be used as a sys.excepthook for Python > 2.1.
896
896
897 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
897 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
898
898
899 Allows a tb_offset to be specified. This is useful for situations where
899 Allows a tb_offset to be specified. This is useful for situations where
900 one needs to remove a number of topmost frames from the traceback (such as
900 one needs to remove a number of topmost frames from the traceback (such as
901 occurs with python programs that themselves execute other python code,
901 occurs with python programs that themselves execute other python code,
902 like Python shells). """
902 like Python shells). """
903
903
904 def __init__(self, mode = 'Plain', color_scheme='Linux',
904 def __init__(self, mode = 'Plain', color_scheme='Linux',
905 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
905 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
906
906
907 # NEVER change the order of this list. Put new modes at the end:
907 # NEVER change the order of this list. Put new modes at the end:
908 self.valid_modes = ['Plain','Context','Verbose']
908 self.valid_modes = ['Plain','Context','Verbose']
909 self.verbose_modes = self.valid_modes[1:3]
909 self.verbose_modes = self.valid_modes[1:3]
910
910
911 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
911 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
912 call_pdb=call_pdb,include_vars=include_vars)
912 call_pdb=call_pdb,include_vars=include_vars)
913 self.set_mode(mode)
913 self.set_mode(mode)
914
914
915 def _extract_tb(self,tb):
915 def _extract_tb(self,tb):
916 if tb:
916 if tb:
917 return traceback.extract_tb(tb)
917 return traceback.extract_tb(tb)
918 else:
918 else:
919 return None
919 return None
920
920
921 def text(self, etype, value, tb,context=5,mode=None):
921 def text(self, etype, value, tb,context=5,mode=None):
922 """Return formatted traceback.
922 """Return formatted traceback.
923
923
924 If the optional mode parameter is given, it overrides the current
924 If the optional mode parameter is given, it overrides the current
925 mode."""
925 mode."""
926
926
927 if mode is None:
927 if mode is None:
928 mode = self.mode
928 mode = self.mode
929 if mode in self.verbose_modes:
929 if mode in self.verbose_modes:
930 # verbose modes need a full traceback
930 # verbose modes need a full traceback
931 return VerboseTB.text(self,etype, value, tb,context=5)
931 return VerboseTB.text(self,etype, value, tb,context=5)
932 else:
932 else:
933 # We must check the source cache because otherwise we can print
933 # We must check the source cache because otherwise we can print
934 # out-of-date source code.
934 # out-of-date source code.
935 linecache.checkcache()
935 linecache.checkcache()
936 # Now we can extract and format the exception
936 # Now we can extract and format the exception
937 elist = self._extract_tb(tb)
937 elist = self._extract_tb(tb)
938 if len(elist) > self.tb_offset:
938 if len(elist) > self.tb_offset:
939 del elist[:self.tb_offset]
939 del elist[:self.tb_offset]
940 return ListTB.text(self,etype,value,elist)
940 return ListTB.text(self,etype,value,elist)
941
941
942 def set_mode(self,mode=None):
942 def set_mode(self,mode=None):
943 """Switch to the desired mode.
943 """Switch to the desired mode.
944
944
945 If mode is not specified, cycles through the available modes."""
945 If mode is not specified, cycles through the available modes."""
946
946
947 if not mode:
947 if not mode:
948 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
948 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
949 len(self.valid_modes)
949 len(self.valid_modes)
950 self.mode = self.valid_modes[new_idx]
950 self.mode = self.valid_modes[new_idx]
951 elif mode not in self.valid_modes:
951 elif mode not in self.valid_modes:
952 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
952 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
953 'Valid modes: '+str(self.valid_modes)
953 'Valid modes: '+str(self.valid_modes)
954 else:
954 else:
955 self.mode = mode
955 self.mode = mode
956 # include variable details only in 'Verbose' mode
956 # include variable details only in 'Verbose' mode
957 self.include_vars = (self.mode == self.valid_modes[2])
957 self.include_vars = (self.mode == self.valid_modes[2])
958
958
959 # some convenient shorcuts
959 # some convenient shorcuts
960 def plain(self):
960 def plain(self):
961 self.set_mode(self.valid_modes[0])
961 self.set_mode(self.valid_modes[0])
962
962
963 def context(self):
963 def context(self):
964 self.set_mode(self.valid_modes[1])
964 self.set_mode(self.valid_modes[1])
965
965
966 def verbose(self):
966 def verbose(self):
967 self.set_mode(self.valid_modes[2])
967 self.set_mode(self.valid_modes[2])
968
968
969 #----------------------------------------------------------------------------
969 #----------------------------------------------------------------------------
970 class AutoFormattedTB(FormattedTB):
970 class AutoFormattedTB(FormattedTB):
971 """A traceback printer which can be called on the fly.
971 """A traceback printer which can be called on the fly.
972
972
973 It will find out about exceptions by itself.
973 It will find out about exceptions by itself.
974
974
975 A brief example:
975 A brief example:
976
976
977 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
977 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
978 try:
978 try:
979 ...
979 ...
980 except:
980 except:
981 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
981 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
982 """
982 """
983 def __call__(self,etype=None,evalue=None,etb=None,
983 def __call__(self,etype=None,evalue=None,etb=None,
984 out=None,tb_offset=None):
984 out=None,tb_offset=None):
985 """Print out a formatted exception traceback.
985 """Print out a formatted exception traceback.
986
986
987 Optional arguments:
987 Optional arguments:
988 - out: an open file-like object to direct output to.
988 - out: an open file-like object to direct output to.
989
989
990 - tb_offset: the number of frames to skip over in the stack, on a
990 - tb_offset: the number of frames to skip over in the stack, on a
991 per-call basis (this overrides temporarily the instance's tb_offset
991 per-call basis (this overrides temporarily the instance's tb_offset
992 given at initialization time. """
992 given at initialization time. """
993
993
994 if out is None:
994 if out is None:
995 out = Term.cerr
995 out = Term.cerr
996 Term.cout.flush()
996 Term.cout.flush()
997 if tb_offset is not None:
997 if tb_offset is not None:
998 tb_offset, self.tb_offset = self.tb_offset, tb_offset
998 tb_offset, self.tb_offset = self.tb_offset, tb_offset
999 print >> out, self.text(etype, evalue, etb)
999 print >> out, self.text(etype, evalue, etb)
1000 self.tb_offset = tb_offset
1000 self.tb_offset = tb_offset
1001 else:
1001 else:
1002 print >> out, self.text(etype, evalue, etb)
1002 print >> out, self.text(etype, evalue, etb)
1003 out.flush()
1003 out.flush()
1004 try:
1004 try:
1005 self.debugger()
1005 self.debugger()
1006 except KeyboardInterrupt:
1006 except KeyboardInterrupt:
1007 print "\nKeyboardInterrupt"
1007 print "\nKeyboardInterrupt"
1008
1008
1009 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1009 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1010 if etype is None:
1010 if etype is None:
1011 etype,value,tb = sys.exc_info()
1011 etype,value,tb = sys.exc_info()
1012 self.tb = tb
1012 self.tb = tb
1013 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1013 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1014
1014
1015 #---------------------------------------------------------------------------
1015 #---------------------------------------------------------------------------
1016 # A simple class to preserve Nathan's original functionality.
1016 # A simple class to preserve Nathan's original functionality.
1017 class ColorTB(FormattedTB):
1017 class ColorTB(FormattedTB):
1018 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1018 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1019 def __init__(self,color_scheme='Linux',call_pdb=0):
1019 def __init__(self,color_scheme='Linux',call_pdb=0):
1020 FormattedTB.__init__(self,color_scheme=color_scheme,
1020 FormattedTB.__init__(self,color_scheme=color_scheme,
1021 call_pdb=call_pdb)
1021 call_pdb=call_pdb)
1022
1022
1023 #----------------------------------------------------------------------------
1023 #----------------------------------------------------------------------------
1024 # module testing (minimal)
1024 # module testing (minimal)
1025 if __name__ == "__main__":
1025 if __name__ == "__main__":
1026 def spam(c, (d, e)):
1026 def spam(c, (d, e)):
1027 x = c + d
1027 x = c + d
1028 y = c * d
1028 y = c * d
1029 foo(x, y)
1029 foo(x, y)
1030
1030
1031 def foo(a, b, bar=1):
1031 def foo(a, b, bar=1):
1032 eggs(a, b + bar)
1032 eggs(a, b + bar)
1033
1033
1034 def eggs(f, g, z=globals()):
1034 def eggs(f, g, z=globals()):
1035 h = f + g
1035 h = f + g
1036 i = f - g
1036 i = f - g
1037 return h / i
1037 return h / i
1038
1038
1039 print ''
1039 print ''
1040 print '*** Before ***'
1040 print '*** Before ***'
1041 try:
1041 try:
1042 print spam(1, (2, 3))
1042 print spam(1, (2, 3))
1043 except:
1043 except:
1044 traceback.print_exc()
1044 traceback.print_exc()
1045 print ''
1045 print ''
1046
1046
1047 handler = ColorTB()
1047 handler = ColorTB()
1048 print '*** ColorTB ***'
1048 print '*** ColorTB ***'
1049 try:
1049 try:
1050 print spam(1, (2, 3))
1050 print spam(1, (2, 3))
1051 except:
1051 except:
1052 apply(handler, sys.exc_info() )
1052 apply(handler, sys.exc_info() )
1053 print ''
1053 print ''
1054
1054
1055 handler = VerboseTB()
1055 handler = VerboseTB()
1056 print '*** VerboseTB ***'
1056 print '*** VerboseTB ***'
1057 try:
1057 try:
1058 print spam(1, (2, 3))
1058 print spam(1, (2, 3))
1059 except:
1059 except:
1060 apply(handler, sys.exc_info() )
1060 apply(handler, sys.exc_info() )
1061 print ''
1061 print ''
1062
1062
General Comments 0
You need to be logged in to leave comments. Login now