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