##// END OF EJS Templates
- R. Bernstein's patches (minor reworks) to provide full syntax highlight in...
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

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