##// END OF EJS Templates
Fix broken %pdb/%debug (signature of DisplayTrap changed)
Fernando Perez -
Show More
@@ -1,1104 +1,1104 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
64 64 #*****************************************************************************
65 65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 67 #
68 68 # Distributed under the terms of the BSD License. The full license is in
69 69 # the file COPYING, distributed as part of this software.
70 70 #*****************************************************************************
71 71
72 72 from __future__ import with_statement
73 73
74 74 import inspect
75 75 import keyword
76 76 import linecache
77 77 import os
78 78 import pydoc
79 79 import re
80 80 import string
81 81 import sys
82 82 import time
83 83 import tokenize
84 84 import traceback
85 85 import types
86 86
87 87 # For purposes of monkeypatching inspect to fix a bug in it.
88 88 from inspect import getsourcefile, getfile, getmodule,\
89 89 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
90 90
91 91 # IPython's own modules
92 92 # Modified pdb which doesn't damage IPython's readline handling
93 93 from IPython.utils import PyColorize
94 94 from IPython.core import debugger, ipapi
95 95 from IPython.core.display_trap import DisplayTrap
96 96 from IPython.core.excolors import exception_colors
97 97 from IPython.utils.data import uniq_stable
98 98 from IPython.utils.io import Term
99 99 from IPython.utils.warn import info, error
100 100
101 101 # Globals
102 102 # amount of space to put line numbers before verbose tracebacks
103 103 INDENT_SIZE = 8
104 104
105 105 # Default color scheme. This is used, for example, by the traceback
106 106 # formatter. When running in an actual IPython instance, the user's rc.colors
107 107 # value is used, but havinga module global makes this functionality available
108 108 # to users of ultratb who are NOT running inside ipython.
109 109 DEFAULT_SCHEME = 'NoColor'
110 110
111 111 #---------------------------------------------------------------------------
112 112 # Code begins
113 113
114 114 # Utility functions
115 115 def inspect_error():
116 116 """Print a message about internal inspect errors.
117 117
118 118 These are unfortunately quite common."""
119 119
120 120 error('Internal Python error in the inspect module.\n'
121 121 'Below is the traceback from this internal error.\n')
122 122
123 123
124 124 def findsource(object):
125 125 """Return the entire source file and starting line number for an object.
126 126
127 127 The argument may be a module, class, method, function, traceback, frame,
128 128 or code object. The source code is returned as a list of all the lines
129 129 in the file and the line number indexes a line in that list. An IOError
130 130 is raised if the source code cannot be retrieved.
131 131
132 132 FIXED version with which we monkeypatch the stdlib to work around a bug."""
133 133
134 134 file = getsourcefile(object) or getfile(object)
135 135 # If the object is a frame, then trying to get the globals dict from its
136 136 # module won't work. Instead, the frame object itself has the globals
137 137 # dictionary.
138 138 globals_dict = None
139 139 if inspect.isframe(object):
140 140 # XXX: can this ever be false?
141 141 globals_dict = object.f_globals
142 142 else:
143 143 module = getmodule(object, file)
144 144 if module:
145 145 globals_dict = module.__dict__
146 146 lines = linecache.getlines(file, globals_dict)
147 147 if not lines:
148 148 raise IOError('could not get source code')
149 149
150 150 if ismodule(object):
151 151 return lines, 0
152 152
153 153 if isclass(object):
154 154 name = object.__name__
155 155 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
156 156 # make some effort to find the best matching class definition:
157 157 # use the one with the least indentation, which is the one
158 158 # that's most probably not inside a function definition.
159 159 candidates = []
160 160 for i in range(len(lines)):
161 161 match = pat.match(lines[i])
162 162 if match:
163 163 # if it's at toplevel, it's already the best one
164 164 if lines[i][0] == 'c':
165 165 return lines, i
166 166 # else add whitespace to candidate list
167 167 candidates.append((match.group(1), i))
168 168 if candidates:
169 169 # this will sort by whitespace, and by line number,
170 170 # less whitespace first
171 171 candidates.sort()
172 172 return lines, candidates[0][1]
173 173 else:
174 174 raise IOError('could not find class definition')
175 175
176 176 if ismethod(object):
177 177 object = object.im_func
178 178 if isfunction(object):
179 179 object = object.func_code
180 180 if istraceback(object):
181 181 object = object.tb_frame
182 182 if isframe(object):
183 183 object = object.f_code
184 184 if iscode(object):
185 185 if not hasattr(object, 'co_firstlineno'):
186 186 raise IOError('could not find function definition')
187 187 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
188 188 pmatch = pat.match
189 189 # fperez - fix: sometimes, co_firstlineno can give a number larger than
190 190 # the length of lines, which causes an error. Safeguard against that.
191 191 lnum = min(object.co_firstlineno,len(lines))-1
192 192 while lnum > 0:
193 193 if pmatch(lines[lnum]): break
194 194 lnum -= 1
195 195
196 196 return lines, lnum
197 197 raise IOError('could not find code object')
198 198
199 199 # Monkeypatch inspect to apply our bugfix. This code only works with py25
200 200 if sys.version_info[:2] >= (2,5):
201 201 inspect.findsource = findsource
202 202
203 203 def fix_frame_records_filenames(records):
204 204 """Try to fix the filenames in each record from inspect.getinnerframes().
205 205
206 206 Particularly, modules loaded from within zip files have useless filenames
207 207 attached to their code object, and inspect.getinnerframes() just uses it.
208 208 """
209 209 fixed_records = []
210 210 for frame, filename, line_no, func_name, lines, index in records:
211 211 # Look inside the frame's globals dictionary for __file__, which should
212 212 # be better.
213 213 better_fn = frame.f_globals.get('__file__', None)
214 214 if isinstance(better_fn, str):
215 215 # Check the type just in case someone did something weird with
216 216 # __file__. It might also be None if the error occurred during
217 217 # import.
218 218 filename = better_fn
219 219 fixed_records.append((frame, filename, line_no, func_name, lines, index))
220 220 return fixed_records
221 221
222 222
223 223 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
224 224 import linecache
225 225 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
226 226
227 227 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
228 228
229 229 # If the error is at the console, don't build any context, since it would
230 230 # otherwise produce 5 blank lines printed out (there is no file at the
231 231 # console)
232 232 rec_check = records[tb_offset:]
233 233 try:
234 234 rname = rec_check[0][1]
235 235 if rname == '<ipython console>' or rname.endswith('<string>'):
236 236 return rec_check
237 237 except IndexError:
238 238 pass
239 239
240 240 aux = traceback.extract_tb(etb)
241 241 assert len(records) == len(aux)
242 242 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
243 243 maybeStart = lnum-1 - context//2
244 244 start = max(maybeStart, 0)
245 245 end = start + context
246 246 lines = linecache.getlines(file)[start:end]
247 247 # pad with empty lines if necessary
248 248 if maybeStart < 0:
249 249 lines = (['\n'] * -maybeStart) + lines
250 250 if len(lines) < context:
251 251 lines += ['\n'] * (context - len(lines))
252 252 buf = list(records[i])
253 253 buf[LNUM_POS] = lnum
254 254 buf[INDEX_POS] = lnum - 1 - start
255 255 buf[LINES_POS] = lines
256 256 records[i] = tuple(buf)
257 257 return records[tb_offset:]
258 258
259 259 # Helper function -- largely belongs to VerboseTB, but we need the same
260 260 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
261 261 # can be recognized properly by ipython.el's py-traceback-line-re
262 262 # (SyntaxErrors have to be treated specially because they have no traceback)
263 263
264 264 _parser = PyColorize.Parser()
265 265
266 266 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
267 267 numbers_width = INDENT_SIZE - 1
268 268 res = []
269 269 i = lnum - index
270 270
271 271 # This lets us get fully syntax-highlighted tracebacks.
272 272 if scheme is None:
273 273 ipinst = ipapi.get()
274 274 if ipinst is not None:
275 275 scheme = ipinst.colors
276 276 else:
277 277 scheme = DEFAULT_SCHEME
278 278
279 279 _line_format = _parser.format2
280 280
281 281 for line in lines:
282 282 new_line, err = _line_format(line,'str',scheme)
283 283 if not err: line = new_line
284 284
285 285 if i == lnum:
286 286 # This is the line with the error
287 287 pad = numbers_width - len(str(i))
288 288 if pad >= 3:
289 289 marker = '-'*(pad-3) + '-> '
290 290 elif pad == 2:
291 291 marker = '> '
292 292 elif pad == 1:
293 293 marker = '>'
294 294 else:
295 295 marker = ''
296 296 num = marker + str(i)
297 297 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 298 Colors.line, line, Colors.Normal)
299 299 else:
300 300 num = '%*s' % (numbers_width,i)
301 301 line = '%s%s%s %s' %(Colors.lineno, num,
302 302 Colors.Normal, line)
303 303
304 304 res.append(line)
305 305 if lvals and i == lnum:
306 306 res.append(lvals + '\n')
307 307 i = i + 1
308 308 return res
309 309
310 310
311 311 #---------------------------------------------------------------------------
312 312 # Module classes
313 313 class TBTools:
314 314 """Basic tools used by all traceback printer classes."""
315 315
316 316 #: Default output stream, can be overridden at call time. A special value
317 317 #: of 'stdout' *as a string* can be given to force extraction of sys.stdout
318 318 #: at runtime. This allows testing exception printing with doctests, that
319 319 #: swap sys.stdout just at execution time.
320 320 #: Warning: be VERY careful to set this to one of the Term streams, NEVER
321 321 #: directly to sys.stdout/err, because under win32 the Term streams come from
322 322 #: pyreadline and know how to handle color correctly, whie stdout/err don't.
323 323 out_stream = Term.cerr
324 324
325 325 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
326 326 # Whether to call the interactive pdb debugger after printing
327 327 # tracebacks or not
328 328 self.call_pdb = call_pdb
329 329
330 330 # Create color table
331 331 self.color_scheme_table = exception_colors()
332 332
333 333 self.set_colors(color_scheme)
334 334 self.old_scheme = color_scheme # save initial value for toggles
335 335
336 336 if call_pdb:
337 337 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
338 338 else:
339 339 self.pdb = None
340 340
341 341 def set_colors(self,*args,**kw):
342 342 """Shorthand access to the color table scheme selector method."""
343 343
344 344 # Set own color table
345 345 self.color_scheme_table.set_active_scheme(*args,**kw)
346 346 # for convenience, set Colors to the active scheme
347 347 self.Colors = self.color_scheme_table.active_colors
348 348 # Also set colors of debugger
349 349 if hasattr(self,'pdb') and self.pdb is not None:
350 350 self.pdb.set_colors(*args,**kw)
351 351
352 352 def color_toggle(self):
353 353 """Toggle between the currently active color scheme and NoColor."""
354 354
355 355 if self.color_scheme_table.active_scheme_name == 'NoColor':
356 356 self.color_scheme_table.set_active_scheme(self.old_scheme)
357 357 self.Colors = self.color_scheme_table.active_colors
358 358 else:
359 359 self.old_scheme = self.color_scheme_table.active_scheme_name
360 360 self.color_scheme_table.set_active_scheme('NoColor')
361 361 self.Colors = self.color_scheme_table.active_colors
362 362
363 363 #---------------------------------------------------------------------------
364 364 class ListTB(TBTools):
365 365 """Print traceback information from a traceback list, with optional color.
366 366
367 367 Calling: requires 3 arguments:
368 368 (etype, evalue, elist)
369 369 as would be obtained by:
370 370 etype, evalue, tb = sys.exc_info()
371 371 if tb:
372 372 elist = traceback.extract_tb(tb)
373 373 else:
374 374 elist = None
375 375
376 376 It can thus be used by programs which need to process the traceback before
377 377 printing (such as console replacements based on the code module from the
378 378 standard library).
379 379
380 380 Because they are meant to be called without a full traceback (only a
381 381 list), instances of this class can't call the interactive pdb debugger."""
382 382
383 383 def __init__(self,color_scheme = 'NoColor'):
384 384 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
385 385
386 386 def __call__(self, etype, value, elist):
387 387 Term.cout.flush()
388 388 Term.cerr.write(self.text(etype,value,elist))
389 389 Term.cerr.write('\n')
390 390
391 391 def text(self, etype, value, elist, context=5):
392 392 """Return a color formatted string with the traceback info.
393 393
394 394 Parameters
395 395 ----------
396 396 etype : exception type
397 397 Type of the exception raised.
398 398
399 399 value : object
400 400 Data stored in the exception
401 401
402 402 elist : list
403 403 List of frames, see class docstring for details.
404 404
405 405 Returns
406 406 -------
407 407 String with formatted exception.
408 408 """
409 409
410 410 Colors = self.Colors
411 411 out_string = []
412 412 if elist:
413 413 out_string.append('Traceback %s(most recent call last)%s:' %
414 414 (Colors.normalEm, Colors.Normal) + '\n')
415 415 out_string.extend(self._format_list(elist))
416 416 lines = self._format_exception_only(etype, value)
417 417 for line in lines[:-1]:
418 418 out_string.append(" "+line)
419 419 out_string.append(lines[-1])
420 420 return ''.join(out_string)
421 421
422 422 def _format_list(self, extracted_list):
423 423 """Format a list of traceback entry tuples for printing.
424 424
425 425 Given a list of tuples as returned by extract_tb() or
426 426 extract_stack(), return a list of strings ready for printing.
427 427 Each string in the resulting list corresponds to the item with the
428 428 same index in the argument list. Each string ends in a newline;
429 429 the strings may contain internal newlines as well, for those items
430 430 whose source text line is not None.
431 431
432 432 Lifted almost verbatim from traceback.py
433 433 """
434 434
435 435 Colors = self.Colors
436 436 list = []
437 437 for filename, lineno, name, line in extracted_list[:-1]:
438 438 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
439 439 (Colors.filename, filename, Colors.Normal,
440 440 Colors.lineno, lineno, Colors.Normal,
441 441 Colors.name, name, Colors.Normal)
442 442 if line:
443 443 item = item + ' %s\n' % line.strip()
444 444 list.append(item)
445 445 # Emphasize the last entry
446 446 filename, lineno, name, line = extracted_list[-1]
447 447 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
448 448 (Colors.normalEm,
449 449 Colors.filenameEm, filename, Colors.normalEm,
450 450 Colors.linenoEm, lineno, Colors.normalEm,
451 451 Colors.nameEm, name, Colors.normalEm,
452 452 Colors.Normal)
453 453 if line:
454 454 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
455 455 Colors.Normal)
456 456 list.append(item)
457 457 return list
458 458
459 459 def _format_exception_only(self, etype, value):
460 460 """Format the exception part of a traceback.
461 461
462 462 The arguments are the exception type and value such as given by
463 463 sys.exc_info()[:2]. The return value is a list of strings, each ending
464 464 in a newline. Normally, the list contains a single string; however,
465 465 for SyntaxError exceptions, it contains several lines that (when
466 466 printed) display detailed information about where the syntax error
467 467 occurred. The message indicating which exception occurred is the
468 468 always last string in the list.
469 469
470 470 Also lifted nearly verbatim from traceback.py
471 471 """
472 472
473 473 have_filedata = False
474 474 Colors = self.Colors
475 475 list = []
476 476 try:
477 477 stype = Colors.excName + etype.__name__ + Colors.Normal
478 478 except AttributeError:
479 479 stype = etype # String exceptions don't get special coloring
480 480 if value is None:
481 481 list.append( str(stype) + '\n')
482 482 else:
483 483 if etype is SyntaxError:
484 484 try:
485 485 msg, (filename, lineno, offset, line) = value
486 486 except:
487 487 have_filedata = False
488 488 else:
489 489 have_filedata = True
490 490 #print 'filename is',filename # dbg
491 491 if not filename: filename = "<string>"
492 492 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
493 493 (Colors.normalEm,
494 494 Colors.filenameEm, filename, Colors.normalEm,
495 495 Colors.linenoEm, lineno, Colors.Normal ))
496 496 if line is not None:
497 497 i = 0
498 498 while i < len(line) and line[i].isspace():
499 499 i = i+1
500 500 list.append('%s %s%s\n' % (Colors.line,
501 501 line.strip(),
502 502 Colors.Normal))
503 503 if offset is not None:
504 504 s = ' '
505 505 for c in line[i:offset-1]:
506 506 if c.isspace():
507 507 s = s + c
508 508 else:
509 509 s = s + ' '
510 510 list.append('%s%s^%s\n' % (Colors.caret, s,
511 511 Colors.Normal) )
512 512 value = msg
513 513 s = self._some_str(value)
514 514 if s:
515 515 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
516 516 Colors.Normal, s))
517 517 else:
518 518 list.append('%s\n' % str(stype))
519 519
520 520 # sync with user hooks
521 521 if have_filedata:
522 522 ipinst = ipapi.get()
523 523 if ipinst is not None:
524 524 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
525 525
526 526 return list
527 527
528 528 def show_exception_only(self, etype, value):
529 529 """Only print the exception type and message, without a traceback.
530 530
531 531 Parameters
532 532 ----------
533 533 etype : exception type
534 534 value : exception value
535 535 """
536 536 # This method needs to use __call__ from *this* class, not the one from
537 537 # a subclass whose signature or behavior may be different
538 538 Term.cout.flush()
539 539 ostream = sys.stdout if self.out_stream == 'stdout' else Term.cerr
540 540 ostream.write(ListTB.text(self, etype, value, []))
541 541 ostream.flush()
542 542
543 543 def _some_str(self, value):
544 544 # Lifted from traceback.py
545 545 try:
546 546 return str(value)
547 547 except:
548 548 return '<unprintable %s object>' % type(value).__name__
549 549
550 550 #----------------------------------------------------------------------------
551 551 class VerboseTB(TBTools):
552 552 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
553 553 of HTML. Requires inspect and pydoc. Crazy, man.
554 554
555 555 Modified version which optionally strips the topmost entries from the
556 556 traceback, to be used with alternate interpreters (because their own code
557 557 would appear in the traceback)."""
558 558
559 559 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
560 560 call_pdb = 0, include_vars=1):
561 561 """Specify traceback offset, headers and color scheme.
562 562
563 563 Define how many frames to drop from the tracebacks. Calling it with
564 564 tb_offset=1 allows use of this handler in interpreters which will have
565 565 their own code at the top of the traceback (VerboseTB will first
566 566 remove that frame before printing the traceback info)."""
567 567 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
568 568 self.tb_offset = tb_offset
569 569 self.long_header = long_header
570 570 self.include_vars = include_vars
571 571
572 572 def text(self, etype, evalue, etb, context=5):
573 573 """Return a nice text document describing the traceback."""
574 574
575 575 # some locals
576 576 try:
577 577 etype = etype.__name__
578 578 except AttributeError:
579 579 pass
580 580 Colors = self.Colors # just a shorthand + quicker name lookup
581 581 ColorsNormal = Colors.Normal # used a lot
582 582 col_scheme = self.color_scheme_table.active_scheme_name
583 583 indent = ' '*INDENT_SIZE
584 584 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
585 585 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
586 586 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
587 587
588 588 # some internal-use functions
589 589 def text_repr(value):
590 590 """Hopefully pretty robust repr equivalent."""
591 591 # this is pretty horrible but should always return *something*
592 592 try:
593 593 return pydoc.text.repr(value)
594 594 except KeyboardInterrupt:
595 595 raise
596 596 except:
597 597 try:
598 598 return repr(value)
599 599 except KeyboardInterrupt:
600 600 raise
601 601 except:
602 602 try:
603 603 # all still in an except block so we catch
604 604 # getattr raising
605 605 name = getattr(value, '__name__', None)
606 606 if name:
607 607 # ick, recursion
608 608 return text_repr(name)
609 609 klass = getattr(value, '__class__', None)
610 610 if klass:
611 611 return '%s instance' % text_repr(klass)
612 612 except KeyboardInterrupt:
613 613 raise
614 614 except:
615 615 return 'UNRECOVERABLE REPR FAILURE'
616 616 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
617 617 def nullrepr(value, repr=text_repr): return ''
618 618
619 619 # meat of the code begins
620 620 try:
621 621 etype = etype.__name__
622 622 except AttributeError:
623 623 pass
624 624
625 625 if self.long_header:
626 626 # Header with the exception type, python version, and date
627 627 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
628 628 date = time.ctime(time.time())
629 629
630 630 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
631 631 exc, ' '*(75-len(str(etype))-len(pyver)),
632 632 pyver, string.rjust(date, 75) )
633 633 head += "\nA problem occured executing Python code. Here is the sequence of function"\
634 634 "\ncalls leading up to the error, with the most recent (innermost) call last."
635 635 else:
636 636 # Simplified header
637 637 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
638 638 string.rjust('Traceback (most recent call last)',
639 639 75 - len(str(etype)) ) )
640 640 frames = []
641 641 # Flush cache before calling inspect. This helps alleviate some of the
642 642 # problems with python 2.3's inspect.py.
643 643 linecache.checkcache()
644 644 # Drop topmost frames if requested
645 645 try:
646 646 # Try the default getinnerframes and Alex's: Alex's fixes some
647 647 # problems, but it generates empty tracebacks for console errors
648 648 # (5 blanks lines) where none should be returned.
649 649 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
650 650 #print 'python records:', records # dbg
651 651 records = _fixed_getinnerframes(etb, context,self.tb_offset)
652 652 #print 'alex records:', records # dbg
653 653 except:
654 654
655 655 # FIXME: I've been getting many crash reports from python 2.3
656 656 # users, traceable to inspect.py. If I can find a small test-case
657 657 # to reproduce this, I should either write a better workaround or
658 658 # file a bug report against inspect (if that's the real problem).
659 659 # So far, I haven't been able to find an isolated example to
660 660 # reproduce the problem.
661 661 inspect_error()
662 662 traceback.print_exc(file=Term.cerr)
663 663 info('\nUnfortunately, your original traceback can not be constructed.\n')
664 664 return ''
665 665
666 666 # build some color string templates outside these nested loops
667 667 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
668 668 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
669 669 ColorsNormal)
670 670 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
671 671 (Colors.vName, Colors.valEm, ColorsNormal)
672 672 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
673 673 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
674 674 Colors.vName, ColorsNormal)
675 675 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
676 676 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
677 677 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
678 678 ColorsNormal)
679 679
680 680 # now, loop over all records printing context and info
681 681 abspath = os.path.abspath
682 682 for frame, file, lnum, func, lines, index in records:
683 683 #print '*** record:',file,lnum,func,lines,index # dbg
684 684 try:
685 685 file = file and abspath(file) or '?'
686 686 except OSError:
687 687 # if file is '<console>' or something not in the filesystem,
688 688 # the abspath call will throw an OSError. Just ignore it and
689 689 # keep the original file string.
690 690 pass
691 691 link = tpl_link % file
692 692 try:
693 693 args, varargs, varkw, locals = inspect.getargvalues(frame)
694 694 except:
695 695 # This can happen due to a bug in python2.3. We should be
696 696 # able to remove this try/except when 2.4 becomes a
697 697 # requirement. Bug details at http://python.org/sf/1005466
698 698 inspect_error()
699 699 traceback.print_exc(file=Term.cerr)
700 700 info("\nIPython's exception reporting continues...\n")
701 701
702 702 if func == '?':
703 703 call = ''
704 704 else:
705 705 # Decide whether to include variable details or not
706 706 var_repr = self.include_vars and eqrepr or nullrepr
707 707 try:
708 708 call = tpl_call % (func,inspect.formatargvalues(args,
709 709 varargs, varkw,
710 710 locals,formatvalue=var_repr))
711 711 except KeyError:
712 712 # Very odd crash from inspect.formatargvalues(). The
713 713 # scenario under which it appeared was a call to
714 714 # view(array,scale) in NumTut.view.view(), where scale had
715 715 # been defined as a scalar (it should be a tuple). Somehow
716 716 # inspect messes up resolving the argument list of view()
717 717 # and barfs out. At some point I should dig into this one
718 718 # and file a bug report about it.
719 719 inspect_error()
720 720 traceback.print_exc(file=Term.cerr)
721 721 info("\nIPython's exception reporting continues...\n")
722 722 call = tpl_call_fail % func
723 723
724 724 # Initialize a list of names on the current line, which the
725 725 # tokenizer below will populate.
726 726 names = []
727 727
728 728 def tokeneater(token_type, token, start, end, line):
729 729 """Stateful tokeneater which builds dotted names.
730 730
731 731 The list of names it appends to (from the enclosing scope) can
732 732 contain repeated composite names. This is unavoidable, since
733 733 there is no way to disambguate partial dotted structures until
734 734 the full list is known. The caller is responsible for pruning
735 735 the final list of duplicates before using it."""
736 736
737 737 # build composite names
738 738 if token == '.':
739 739 try:
740 740 names[-1] += '.'
741 741 # store state so the next token is added for x.y.z names
742 742 tokeneater.name_cont = True
743 743 return
744 744 except IndexError:
745 745 pass
746 746 if token_type == tokenize.NAME and token not in keyword.kwlist:
747 747 if tokeneater.name_cont:
748 748 # Dotted names
749 749 names[-1] += token
750 750 tokeneater.name_cont = False
751 751 else:
752 752 # Regular new names. We append everything, the caller
753 753 # will be responsible for pruning the list later. It's
754 754 # very tricky to try to prune as we go, b/c composite
755 755 # names can fool us. The pruning at the end is easy
756 756 # to do (or the caller can print a list with repeated
757 757 # names if so desired.
758 758 names.append(token)
759 759 elif token_type == tokenize.NEWLINE:
760 760 raise IndexError
761 761 # we need to store a bit of state in the tokenizer to build
762 762 # dotted names
763 763 tokeneater.name_cont = False
764 764
765 765 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
766 766 line = getline(file, lnum[0])
767 767 lnum[0] += 1
768 768 return line
769 769
770 770 # Build the list of names on this line of code where the exception
771 771 # occurred.
772 772 try:
773 773 # This builds the names list in-place by capturing it from the
774 774 # enclosing scope.
775 775 tokenize.tokenize(linereader, tokeneater)
776 776 except IndexError:
777 777 # signals exit of tokenizer
778 778 pass
779 779 except tokenize.TokenError,msg:
780 780 _m = ("An unexpected error occurred while tokenizing input\n"
781 781 "The following traceback may be corrupted or invalid\n"
782 782 "The error message is: %s\n" % msg)
783 783 error(_m)
784 784
785 785 # prune names list of duplicates, but keep the right order
786 786 unique_names = uniq_stable(names)
787 787
788 788 # Start loop over vars
789 789 lvals = []
790 790 if self.include_vars:
791 791 for name_full in unique_names:
792 792 name_base = name_full.split('.',1)[0]
793 793 if name_base in frame.f_code.co_varnames:
794 794 if locals.has_key(name_base):
795 795 try:
796 796 value = repr(eval(name_full,locals))
797 797 except:
798 798 value = undefined
799 799 else:
800 800 value = undefined
801 801 name = tpl_local_var % name_full
802 802 else:
803 803 if frame.f_globals.has_key(name_base):
804 804 try:
805 805 value = repr(eval(name_full,frame.f_globals))
806 806 except:
807 807 value = undefined
808 808 else:
809 809 value = undefined
810 810 name = tpl_global_var % name_full
811 811 lvals.append(tpl_name_val % (name,value))
812 812 if lvals:
813 813 lvals = '%s%s' % (indent,em_normal.join(lvals))
814 814 else:
815 815 lvals = ''
816 816
817 817 level = '%s %s\n' % (link,call)
818 818
819 819 if index is None:
820 820 frames.append(level)
821 821 else:
822 822 frames.append('%s%s' % (level,''.join(
823 823 _format_traceback_lines(lnum,index,lines,Colors,lvals,
824 824 col_scheme))))
825 825
826 826 # Get (safely) a string form of the exception info
827 827 try:
828 828 etype_str,evalue_str = map(str,(etype,evalue))
829 829 except:
830 830 # User exception is improperly defined.
831 831 etype,evalue = str,sys.exc_info()[:2]
832 832 etype_str,evalue_str = map(str,(etype,evalue))
833 833 # ... and format it
834 834 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
835 835 ColorsNormal, evalue_str)]
836 836 if type(evalue) is types.InstanceType:
837 837 try:
838 838 names = [w for w in dir(evalue) if isinstance(w, basestring)]
839 839 except:
840 840 # Every now and then, an object with funny inernals blows up
841 841 # when dir() is called on it. We do the best we can to report
842 842 # the problem and continue
843 843 _m = '%sException reporting error (object with broken dir())%s:'
844 844 exception.append(_m % (Colors.excName,ColorsNormal))
845 845 etype_str,evalue_str = map(str,sys.exc_info()[:2])
846 846 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
847 847 ColorsNormal, evalue_str))
848 848 names = []
849 849 for name in names:
850 850 value = text_repr(getattr(evalue, name))
851 851 exception.append('\n%s%s = %s' % (indent, name, value))
852 852
853 853 # vds: >>
854 854 if records:
855 855 filepath, lnum = records[-1][1:3]
856 856 #print "file:", str(file), "linenb", str(lnum) # dbg
857 857 filepath = os.path.abspath(filepath)
858 858 ipinst = ipapi.get()
859 859 if ipinst is not None:
860 860 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
861 861 # vds: <<
862 862
863 863 # return all our info assembled as a single string
864 864 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
865 865
866 866 def debugger(self,force=False):
867 867 """Call up the pdb debugger if desired, always clean up the tb
868 868 reference.
869 869
870 870 Keywords:
871 871
872 872 - force(False): by default, this routine checks the instance call_pdb
873 873 flag and does not actually invoke the debugger if the flag is false.
874 874 The 'force' option forces the debugger to activate even if the flag
875 875 is false.
876 876
877 877 If the call_pdb flag is set, the pdb interactive debugger is
878 878 invoked. In all cases, the self.tb reference to the current traceback
879 879 is deleted to prevent lingering references which hamper memory
880 880 management.
881 881
882 882 Note that each call to pdb() does an 'import readline', so if your app
883 883 requires a special setup for the readline completers, you'll have to
884 884 fix that by hand after invoking the exception handler."""
885 885
886 886 if force or self.call_pdb:
887 887 if self.pdb is None:
888 888 self.pdb = debugger.Pdb(
889 889 self.color_scheme_table.active_scheme_name)
890 890 # the system displayhook may have changed, restore the original
891 891 # for pdb
892 display_trap = DisplayTrap(None, sys.__displayhook__)
892 display_trap = DisplayTrap(hook=sys.__displayhook__)
893 893 with display_trap:
894 894 self.pdb.reset()
895 895 # Find the right frame so we don't pop up inside ipython itself
896 896 if hasattr(self,'tb') and self.tb is not None:
897 897 etb = self.tb
898 898 else:
899 899 etb = self.tb = sys.last_traceback
900 900 while self.tb is not None and self.tb.tb_next is not None:
901 901 self.tb = self.tb.tb_next
902 902 if etb and etb.tb_next:
903 903 etb = etb.tb_next
904 904 self.pdb.botframe = etb.tb_frame
905 905 self.pdb.interaction(self.tb.tb_frame, self.tb)
906 906
907 907 if hasattr(self,'tb'):
908 908 del self.tb
909 909
910 910 def handler(self, info=None):
911 911 (etype, evalue, etb) = info or sys.exc_info()
912 912 self.tb = etb
913 913 Term.cout.flush()
914 914 Term.cerr.write(self.text(etype, evalue, etb))
915 915 Term.cerr.write('\n')
916 916
917 917 # Changed so an instance can just be called as VerboseTB_inst() and print
918 918 # out the right info on its own.
919 919 def __call__(self, etype=None, evalue=None, etb=None):
920 920 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
921 921 if etb is None:
922 922 self.handler()
923 923 else:
924 924 self.handler((etype, evalue, etb))
925 925 try:
926 926 self.debugger()
927 927 except KeyboardInterrupt:
928 928 print "\nKeyboardInterrupt"
929 929
930 930 #----------------------------------------------------------------------------
931 931 class FormattedTB(VerboseTB,ListTB):
932 932 """Subclass ListTB but allow calling with a traceback.
933 933
934 934 It can thus be used as a sys.excepthook for Python > 2.1.
935 935
936 936 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
937 937
938 938 Allows a tb_offset to be specified. This is useful for situations where
939 939 one needs to remove a number of topmost frames from the traceback (such as
940 940 occurs with python programs that themselves execute other python code,
941 941 like Python shells). """
942 942
943 943 def __init__(self, mode = 'Plain', color_scheme='Linux',
944 944 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
945 945
946 946 # NEVER change the order of this list. Put new modes at the end:
947 947 self.valid_modes = ['Plain','Context','Verbose']
948 948 self.verbose_modes = self.valid_modes[1:3]
949 949
950 950 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
951 951 call_pdb=call_pdb,include_vars=include_vars)
952 952 self.set_mode(mode)
953 953
954 954 def _extract_tb(self,tb):
955 955 if tb:
956 956 return traceback.extract_tb(tb)
957 957 else:
958 958 return None
959 959
960 960 def text(self, etype, value, tb,context=5,mode=None):
961 961 """Return formatted traceback.
962 962
963 963 If the optional mode parameter is given, it overrides the current
964 964 mode."""
965 965
966 966 if mode is None:
967 967 mode = self.mode
968 968 if mode in self.verbose_modes:
969 969 # verbose modes need a full traceback
970 970 return VerboseTB.text(self,etype, value, tb,context=5)
971 971 else:
972 972 # We must check the source cache because otherwise we can print
973 973 # out-of-date source code.
974 974 linecache.checkcache()
975 975 # Now we can extract and format the exception
976 976 elist = self._extract_tb(tb)
977 977 if len(elist) > self.tb_offset:
978 978 del elist[:self.tb_offset]
979 979 return ListTB.text(self,etype,value,elist)
980 980
981 981 def set_mode(self,mode=None):
982 982 """Switch to the desired mode.
983 983
984 984 If mode is not specified, cycles through the available modes."""
985 985
986 986 if not mode:
987 987 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
988 988 len(self.valid_modes)
989 989 self.mode = self.valid_modes[new_idx]
990 990 elif mode not in self.valid_modes:
991 991 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
992 992 'Valid modes: '+str(self.valid_modes)
993 993 else:
994 994 self.mode = mode
995 995 # include variable details only in 'Verbose' mode
996 996 self.include_vars = (self.mode == self.valid_modes[2])
997 997
998 998 # some convenient shorcuts
999 999 def plain(self):
1000 1000 self.set_mode(self.valid_modes[0])
1001 1001
1002 1002 def context(self):
1003 1003 self.set_mode(self.valid_modes[1])
1004 1004
1005 1005 def verbose(self):
1006 1006 self.set_mode(self.valid_modes[2])
1007 1007
1008 1008 #----------------------------------------------------------------------------
1009 1009 class AutoFormattedTB(FormattedTB):
1010 1010 """A traceback printer which can be called on the fly.
1011 1011
1012 1012 It will find out about exceptions by itself.
1013 1013
1014 1014 A brief example:
1015 1015
1016 1016 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1017 1017 try:
1018 1018 ...
1019 1019 except:
1020 1020 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1021 1021 """
1022 1022
1023 1023 def __call__(self,etype=None,evalue=None,etb=None,
1024 1024 out=None,tb_offset=None):
1025 1025 """Print out a formatted exception traceback.
1026 1026
1027 1027 Optional arguments:
1028 1028 - out: an open file-like object to direct output to.
1029 1029
1030 1030 - tb_offset: the number of frames to skip over in the stack, on a
1031 1031 per-call basis (this overrides temporarily the instance's tb_offset
1032 1032 given at initialization time. """
1033 1033
1034 1034 if out is None:
1035 1035 out = sys.stdout if self.out_stream=='stdout' else self.out_stream
1036 1036 Term.cout.flush()
1037 1037 if tb_offset is not None:
1038 1038 tb_offset, self.tb_offset = self.tb_offset, tb_offset
1039 1039 out.write(self.text(etype, evalue, etb))
1040 1040 out.write('\n')
1041 1041 self.tb_offset = tb_offset
1042 1042 else:
1043 1043 out.write(self.text(etype, evalue, etb))
1044 1044 out.write('\n')
1045 1045 out.flush()
1046 1046 try:
1047 1047 self.debugger()
1048 1048 except KeyboardInterrupt:
1049 1049 print "\nKeyboardInterrupt"
1050 1050
1051 1051 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1052 1052 if etype is None:
1053 1053 etype,value,tb = sys.exc_info()
1054 1054 self.tb = tb
1055 1055 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1056 1056
1057 1057 #---------------------------------------------------------------------------
1058 1058 # A simple class to preserve Nathan's original functionality.
1059 1059 class ColorTB(FormattedTB):
1060 1060 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1061 1061 def __init__(self,color_scheme='Linux',call_pdb=0):
1062 1062 FormattedTB.__init__(self,color_scheme=color_scheme,
1063 1063 call_pdb=call_pdb)
1064 1064
1065 1065 #----------------------------------------------------------------------------
1066 1066 # module testing (minimal)
1067 1067 if __name__ == "__main__":
1068 1068 def spam(c, (d, e)):
1069 1069 x = c + d
1070 1070 y = c * d
1071 1071 foo(x, y)
1072 1072
1073 1073 def foo(a, b, bar=1):
1074 1074 eggs(a, b + bar)
1075 1075
1076 1076 def eggs(f, g, z=globals()):
1077 1077 h = f + g
1078 1078 i = f - g
1079 1079 return h / i
1080 1080
1081 1081 print ''
1082 1082 print '*** Before ***'
1083 1083 try:
1084 1084 print spam(1, (2, 3))
1085 1085 except:
1086 1086 traceback.print_exc()
1087 1087 print ''
1088 1088
1089 1089 handler = ColorTB()
1090 1090 print '*** ColorTB ***'
1091 1091 try:
1092 1092 print spam(1, (2, 3))
1093 1093 except:
1094 1094 apply(handler, sys.exc_info() )
1095 1095 print ''
1096 1096
1097 1097 handler = VerboseTB()
1098 1098 print '*** VerboseTB ***'
1099 1099 try:
1100 1100 print spam(1, (2, 3))
1101 1101 except:
1102 1102 apply(handler, sys.exc_info() )
1103 1103 print ''
1104 1104
General Comments 0
You need to be logged in to leave comments. Login now