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