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