##// END OF EJS Templates
Fix minor error that I saw in some odd cases, not sure how to test for it....
Fernando Perez -
Show More
@@ -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
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
92 92 # IPython's own modules
93 93 # Modified pdb which doesn't damage IPython's readline handling
94 94 from IPython.utils import PyColorize
95 95 from IPython.core import debugger, ipapi
96 96 from IPython.core.display_trap import DisplayTrap
97 97 from IPython.utils.ipstruct import Struct
98 98 from IPython.core.excolors import exception_colors
99 99 from IPython.utils.genutils import Term, uniq_stable, error, info
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 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
317 317 # Whether to call the interactive pdb debugger after printing
318 318 # tracebacks or not
319 319 self.call_pdb = call_pdb
320 320
321 321 # Create color table
322 322 self.color_scheme_table = exception_colors()
323 323
324 324 self.set_colors(color_scheme)
325 325 self.old_scheme = color_scheme # save initial value for toggles
326 326
327 327 if call_pdb:
328 328 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
329 329 else:
330 330 self.pdb = None
331 331
332 332 def set_colors(self,*args,**kw):
333 333 """Shorthand access to the color table scheme selector method."""
334 334
335 335 # Set own color table
336 336 self.color_scheme_table.set_active_scheme(*args,**kw)
337 337 # for convenience, set Colors to the active scheme
338 338 self.Colors = self.color_scheme_table.active_colors
339 339 # Also set colors of debugger
340 340 if hasattr(self,'pdb') and self.pdb is not None:
341 341 self.pdb.set_colors(*args,**kw)
342 342
343 343 def color_toggle(self):
344 344 """Toggle between the currently active color scheme and NoColor."""
345 345
346 346 if self.color_scheme_table.active_scheme_name == 'NoColor':
347 347 self.color_scheme_table.set_active_scheme(self.old_scheme)
348 348 self.Colors = self.color_scheme_table.active_colors
349 349 else:
350 350 self.old_scheme = self.color_scheme_table.active_scheme_name
351 351 self.color_scheme_table.set_active_scheme('NoColor')
352 352 self.Colors = self.color_scheme_table.active_colors
353 353
354 354 #---------------------------------------------------------------------------
355 355 class ListTB(TBTools):
356 356 """Print traceback information from a traceback list, with optional color.
357 357
358 358 Calling: requires 3 arguments:
359 359 (etype, evalue, elist)
360 360 as would be obtained by:
361 361 etype, evalue, tb = sys.exc_info()
362 362 if tb:
363 363 elist = traceback.extract_tb(tb)
364 364 else:
365 365 elist = None
366 366
367 367 It can thus be used by programs which need to process the traceback before
368 368 printing (such as console replacements based on the code module from the
369 369 standard library).
370 370
371 371 Because they are meant to be called without a full traceback (only a
372 372 list), instances of this class can't call the interactive pdb debugger."""
373 373
374 374 def __init__(self,color_scheme = 'NoColor'):
375 375 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
376 376
377 377 def __call__(self, etype, value, elist):
378 378 Term.cout.flush()
379 379 print >> Term.cerr, self.text(etype,value,elist)
380 380 Term.cerr.flush()
381 381
382 382 def text(self,etype, value, elist,context=5):
383 383 """Return a color formatted string with the traceback info."""
384 384
385 385 Colors = self.Colors
386 386 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
387 387 if elist:
388 388 out_string.append('Traceback %s(most recent call last)%s:' % \
389 389 (Colors.normalEm, Colors.Normal) + '\n')
390 390 out_string.extend(self._format_list(elist))
391 391 lines = self._format_exception_only(etype, value)
392 392 for line in lines[:-1]:
393 393 out_string.append(" "+line)
394 394 out_string.append(lines[-1])
395 395 return ''.join(out_string)
396 396
397 397 def _format_list(self, extracted_list):
398 398 """Format a list of traceback entry tuples for printing.
399 399
400 400 Given a list of tuples as returned by extract_tb() or
401 401 extract_stack(), return a list of strings ready for printing.
402 402 Each string in the resulting list corresponds to the item with the
403 403 same index in the argument list. Each string ends in a newline;
404 404 the strings may contain internal newlines as well, for those items
405 405 whose source text line is not None.
406 406
407 407 Lifted almost verbatim from traceback.py
408 408 """
409 409
410 410 Colors = self.Colors
411 411 list = []
412 412 for filename, lineno, name, line in extracted_list[:-1]:
413 413 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
414 414 (Colors.filename, filename, Colors.Normal,
415 415 Colors.lineno, lineno, Colors.Normal,
416 416 Colors.name, name, Colors.Normal)
417 417 if line:
418 418 item = item + ' %s\n' % line.strip()
419 419 list.append(item)
420 420 # Emphasize the last entry
421 421 filename, lineno, name, line = extracted_list[-1]
422 422 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
423 423 (Colors.normalEm,
424 424 Colors.filenameEm, filename, Colors.normalEm,
425 425 Colors.linenoEm, lineno, Colors.normalEm,
426 426 Colors.nameEm, name, Colors.normalEm,
427 427 Colors.Normal)
428 428 if line:
429 429 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
430 430 Colors.Normal)
431 431 list.append(item)
432 432 return list
433 433
434 434 def _format_exception_only(self, etype, value):
435 435 """Format the exception part of a traceback.
436 436
437 437 The arguments are the exception type and value such as given by
438 438 sys.exc_info()[:2]. The return value is a list of strings, each ending
439 439 in a newline. Normally, the list contains a single string; however,
440 440 for SyntaxError exceptions, it contains several lines that (when
441 441 printed) display detailed information about where the syntax error
442 442 occurred. The message indicating which exception occurred is the
443 443 always last string in the list.
444 444
445 445 Also lifted nearly verbatim from traceback.py
446 446 """
447 447
448 448 have_filedata = False
449 449 Colors = self.Colors
450 450 list = []
451 451 try:
452 452 stype = Colors.excName + etype.__name__ + Colors.Normal
453 453 except AttributeError:
454 454 stype = etype # String exceptions don't get special coloring
455 455 if value is None:
456 456 list.append( str(stype) + '\n')
457 457 else:
458 458 if etype is SyntaxError:
459 459 try:
460 460 msg, (filename, lineno, offset, line) = value
461 461 except:
462 462 have_filedata = False
463 463 else:
464 464 have_filedata = True
465 465 #print 'filename is',filename # dbg
466 466 if not filename: filename = "<string>"
467 467 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 468 (Colors.normalEm,
469 469 Colors.filenameEm, filename, Colors.normalEm,
470 470 Colors.linenoEm, lineno, Colors.Normal ))
471 471 if line is not None:
472 472 i = 0
473 473 while i < len(line) and line[i].isspace():
474 474 i = i+1
475 475 list.append('%s %s%s\n' % (Colors.line,
476 476 line.strip(),
477 477 Colors.Normal))
478 478 if offset is not None:
479 479 s = ' '
480 480 for c in line[i:offset-1]:
481 481 if c.isspace():
482 482 s = s + c
483 483 else:
484 484 s = s + ' '
485 485 list.append('%s%s^%s\n' % (Colors.caret, s,
486 486 Colors.Normal) )
487 487 value = msg
488 488 s = self._some_str(value)
489 489 if s:
490 490 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
491 491 Colors.Normal, s))
492 492 else:
493 493 list.append('%s\n' % str(stype))
494 494
495 495 # vds:>>
496 496 if have_filedata:
497 497 ipinst = ipapi.get()
498 498 if ipinst is not None:
499 499 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
500 500 # vds:<<
501 501
502 502 return list
503 503
504 504 def _some_str(self, value):
505 505 # Lifted from traceback.py
506 506 try:
507 507 return str(value)
508 508 except:
509 509 return '<unprintable %s object>' % type(value).__name__
510 510
511 511 #----------------------------------------------------------------------------
512 512 class VerboseTB(TBTools):
513 513 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
514 514 of HTML. Requires inspect and pydoc. Crazy, man.
515 515
516 516 Modified version which optionally strips the topmost entries from the
517 517 traceback, to be used with alternate interpreters (because their own code
518 518 would appear in the traceback)."""
519 519
520 520 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
521 521 call_pdb = 0, include_vars=1):
522 522 """Specify traceback offset, headers and color scheme.
523 523
524 524 Define how many frames to drop from the tracebacks. Calling it with
525 525 tb_offset=1 allows use of this handler in interpreters which will have
526 526 their own code at the top of the traceback (VerboseTB will first
527 527 remove that frame before printing the traceback info)."""
528 528 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
529 529 self.tb_offset = tb_offset
530 530 self.long_header = long_header
531 531 self.include_vars = include_vars
532 532
533 533 def text(self, etype, evalue, etb, context=5):
534 534 """Return a nice text document describing the traceback."""
535 535
536 536 # some locals
537 537 try:
538 538 etype = etype.__name__
539 539 except AttributeError:
540 540 pass
541 541 Colors = self.Colors # just a shorthand + quicker name lookup
542 542 ColorsNormal = Colors.Normal # used a lot
543 543 col_scheme = self.color_scheme_table.active_scheme_name
544 544 indent = ' '*INDENT_SIZE
545 545 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
546 546 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
547 547 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
548 548
549 549 # some internal-use functions
550 550 def text_repr(value):
551 551 """Hopefully pretty robust repr equivalent."""
552 552 # this is pretty horrible but should always return *something*
553 553 try:
554 554 return pydoc.text.repr(value)
555 555 except KeyboardInterrupt:
556 556 raise
557 557 except:
558 558 try:
559 559 return repr(value)
560 560 except KeyboardInterrupt:
561 561 raise
562 562 except:
563 563 try:
564 564 # all still in an except block so we catch
565 565 # getattr raising
566 566 name = getattr(value, '__name__', None)
567 567 if name:
568 568 # ick, recursion
569 569 return text_repr(name)
570 570 klass = getattr(value, '__class__', None)
571 571 if klass:
572 572 return '%s instance' % text_repr(klass)
573 573 except KeyboardInterrupt:
574 574 raise
575 575 except:
576 576 return 'UNRECOVERABLE REPR FAILURE'
577 577 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
578 578 def nullrepr(value, repr=text_repr): return ''
579 579
580 580 # meat of the code begins
581 581 try:
582 582 etype = etype.__name__
583 583 except AttributeError:
584 584 pass
585 585
586 586 if self.long_header:
587 587 # Header with the exception type, python version, and date
588 588 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
589 589 date = time.ctime(time.time())
590 590
591 591 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
592 592 exc, ' '*(75-len(str(etype))-len(pyver)),
593 593 pyver, string.rjust(date, 75) )
594 594 head += "\nA problem occured executing Python code. Here is the sequence of function"\
595 595 "\ncalls leading up to the error, with the most recent (innermost) call last."
596 596 else:
597 597 # Simplified header
598 598 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
599 599 string.rjust('Traceback (most recent call last)',
600 600 75 - len(str(etype)) ) )
601 601 frames = []
602 602 # Flush cache before calling inspect. This helps alleviate some of the
603 603 # problems with python 2.3's inspect.py.
604 604 linecache.checkcache()
605 605 # Drop topmost frames if requested
606 606 try:
607 607 # Try the default getinnerframes and Alex's: Alex's fixes some
608 608 # problems, but it generates empty tracebacks for console errors
609 609 # (5 blanks lines) where none should be returned.
610 610 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
611 611 #print 'python records:', records # dbg
612 612 records = _fixed_getinnerframes(etb, context,self.tb_offset)
613 613 #print 'alex records:', records # dbg
614 614 except:
615 615
616 616 # FIXME: I've been getting many crash reports from python 2.3
617 617 # users, traceable to inspect.py. If I can find a small test-case
618 618 # to reproduce this, I should either write a better workaround or
619 619 # file a bug report against inspect (if that's the real problem).
620 620 # So far, I haven't been able to find an isolated example to
621 621 # reproduce the problem.
622 622 inspect_error()
623 623 traceback.print_exc(file=Term.cerr)
624 624 info('\nUnfortunately, your original traceback can not be constructed.\n')
625 625 return ''
626 626
627 627 # build some color string templates outside these nested loops
628 628 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
629 629 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
630 630 ColorsNormal)
631 631 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
632 632 (Colors.vName, Colors.valEm, ColorsNormal)
633 633 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
634 634 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
635 635 Colors.vName, ColorsNormal)
636 636 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
637 637 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
638 638 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
639 639 ColorsNormal)
640 640
641 641 # now, loop over all records printing context and info
642 642 abspath = os.path.abspath
643 643 for frame, file, lnum, func, lines, index in records:
644 644 #print '*** record:',file,lnum,func,lines,index # dbg
645 645 try:
646 646 file = file and abspath(file) or '?'
647 647 except OSError:
648 648 # if file is '<console>' or something not in the filesystem,
649 649 # the abspath call will throw an OSError. Just ignore it and
650 650 # keep the original file string.
651 651 pass
652 652 link = tpl_link % file
653 653 try:
654 654 args, varargs, varkw, locals = inspect.getargvalues(frame)
655 655 except:
656 656 # This can happen due to a bug in python2.3. We should be
657 657 # able to remove this try/except when 2.4 becomes a
658 658 # requirement. Bug details at http://python.org/sf/1005466
659 659 inspect_error()
660 660 traceback.print_exc(file=Term.cerr)
661 661 info("\nIPython's exception reporting continues...\n")
662 662
663 663 if func == '?':
664 664 call = ''
665 665 else:
666 666 # Decide whether to include variable details or not
667 667 var_repr = self.include_vars and eqrepr or nullrepr
668 668 try:
669 669 call = tpl_call % (func,inspect.formatargvalues(args,
670 670 varargs, varkw,
671 671 locals,formatvalue=var_repr))
672 672 except KeyError:
673 673 # Very odd crash from inspect.formatargvalues(). The
674 674 # scenario under which it appeared was a call to
675 675 # view(array,scale) in NumTut.view.view(), where scale had
676 676 # been defined as a scalar (it should be a tuple). Somehow
677 677 # inspect messes up resolving the argument list of view()
678 678 # and barfs out. At some point I should dig into this one
679 679 # and file a bug report about it.
680 680 inspect_error()
681 681 traceback.print_exc(file=Term.cerr)
682 682 info("\nIPython's exception reporting continues...\n")
683 683 call = tpl_call_fail % func
684 684
685 685 # Initialize a list of names on the current line, which the
686 686 # tokenizer below will populate.
687 687 names = []
688 688
689 689 def tokeneater(token_type, token, start, end, line):
690 690 """Stateful tokeneater which builds dotted names.
691 691
692 692 The list of names it appends to (from the enclosing scope) can
693 693 contain repeated composite names. This is unavoidable, since
694 694 there is no way to disambguate partial dotted structures until
695 695 the full list is known. The caller is responsible for pruning
696 696 the final list of duplicates before using it."""
697 697
698 698 # build composite names
699 699 if token == '.':
700 700 try:
701 701 names[-1] += '.'
702 702 # store state so the next token is added for x.y.z names
703 703 tokeneater.name_cont = True
704 704 return
705 705 except IndexError:
706 706 pass
707 707 if token_type == tokenize.NAME and token not in keyword.kwlist:
708 708 if tokeneater.name_cont:
709 709 # Dotted names
710 710 names[-1] += token
711 711 tokeneater.name_cont = False
712 712 else:
713 713 # Regular new names. We append everything, the caller
714 714 # will be responsible for pruning the list later. It's
715 715 # very tricky to try to prune as we go, b/c composite
716 716 # names can fool us. The pruning at the end is easy
717 717 # to do (or the caller can print a list with repeated
718 718 # names if so desired.
719 719 names.append(token)
720 720 elif token_type == tokenize.NEWLINE:
721 721 raise IndexError
722 722 # we need to store a bit of state in the tokenizer to build
723 723 # dotted names
724 724 tokeneater.name_cont = False
725 725
726 726 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
727 727 line = getline(file, lnum[0])
728 728 lnum[0] += 1
729 729 return line
730 730
731 731 # Build the list of names on this line of code where the exception
732 732 # occurred.
733 733 try:
734 734 # This builds the names list in-place by capturing it from the
735 735 # enclosing scope.
736 736 tokenize.tokenize(linereader, tokeneater)
737 737 except IndexError:
738 738 # signals exit of tokenizer
739 739 pass
740 740 except tokenize.TokenError,msg:
741 741 _m = ("An unexpected error occurred while tokenizing input\n"
742 742 "The following traceback may be corrupted or invalid\n"
743 743 "The error message is: %s\n" % msg)
744 744 error(_m)
745 745
746 746 # prune names list of duplicates, but keep the right order
747 747 unique_names = uniq_stable(names)
748 748
749 749 # Start loop over vars
750 750 lvals = []
751 751 if self.include_vars:
752 752 for name_full in unique_names:
753 753 name_base = name_full.split('.',1)[0]
754 754 if name_base in frame.f_code.co_varnames:
755 755 if locals.has_key(name_base):
756 756 try:
757 757 value = repr(eval(name_full,locals))
758 758 except:
759 759 value = undefined
760 760 else:
761 761 value = undefined
762 762 name = tpl_local_var % name_full
763 763 else:
764 764 if frame.f_globals.has_key(name_base):
765 765 try:
766 766 value = repr(eval(name_full,frame.f_globals))
767 767 except:
768 768 value = undefined
769 769 else:
770 770 value = undefined
771 771 name = tpl_global_var % name_full
772 772 lvals.append(tpl_name_val % (name,value))
773 773 if lvals:
774 774 lvals = '%s%s' % (indent,em_normal.join(lvals))
775 775 else:
776 776 lvals = ''
777 777
778 778 level = '%s %s\n' % (link,call)
779 779
780 780 if index is None:
781 781 frames.append(level)
782 782 else:
783 783 frames.append('%s%s' % (level,''.join(
784 784 _format_traceback_lines(lnum,index,lines,Colors,lvals,
785 785 col_scheme))))
786 786
787 787 # Get (safely) a string form of the exception info
788 788 try:
789 789 etype_str,evalue_str = map(str,(etype,evalue))
790 790 except:
791 791 # User exception is improperly defined.
792 792 etype,evalue = str,sys.exc_info()[:2]
793 793 etype_str,evalue_str = map(str,(etype,evalue))
794 794 # ... and format it
795 795 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
796 796 ColorsNormal, evalue_str)]
797 797 if type(evalue) is types.InstanceType:
798 798 try:
799 799 names = [w for w in dir(evalue) if isinstance(w, basestring)]
800 800 except:
801 801 # Every now and then, an object with funny inernals blows up
802 802 # when dir() is called on it. We do the best we can to report
803 803 # the problem and continue
804 804 _m = '%sException reporting error (object with broken dir())%s:'
805 805 exception.append(_m % (Colors.excName,ColorsNormal))
806 806 etype_str,evalue_str = map(str,sys.exc_info()[:2])
807 807 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
808 808 ColorsNormal, evalue_str))
809 809 names = []
810 810 for name in names:
811 811 value = text_repr(getattr(evalue, name))
812 812 exception.append('\n%s%s = %s' % (indent, name, value))
813 813
814 814 # vds: >>
815 815 if records:
816 816 filepath, lnum = records[-1][1:3]
817 817 #print "file:", str(file), "linenb", str(lnum) # dbg
818 818 filepath = os.path.abspath(filepath)
819 819 ipinst = ipapi.get()
820 820 if ipinst is not None:
821 821 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
822 822 # vds: <<
823 823
824 824 # return all our info assembled as a single string
825 825 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
826 826
827 827 def debugger(self,force=False):
828 828 """Call up the pdb debugger if desired, always clean up the tb
829 829 reference.
830 830
831 831 Keywords:
832 832
833 833 - force(False): by default, this routine checks the instance call_pdb
834 834 flag and does not actually invoke the debugger if the flag is false.
835 835 The 'force' option forces the debugger to activate even if the flag
836 836 is false.
837 837
838 838 If the call_pdb flag is set, the pdb interactive debugger is
839 839 invoked. In all cases, the self.tb reference to the current traceback
840 840 is deleted to prevent lingering references which hamper memory
841 841 management.
842 842
843 843 Note that each call to pdb() does an 'import readline', so if your app
844 844 requires a special setup for the readline completers, you'll have to
845 845 fix that by hand after invoking the exception handler."""
846 846
847 847 if force or self.call_pdb:
848 848 if self.pdb is None:
849 849 self.pdb = debugger.Pdb(
850 850 self.color_scheme_table.active_scheme_name)
851 851 # the system displayhook may have changed, restore the original
852 852 # for pdb
853 853 display_trap = DisplayTrap(None, sys.__displayhook__)
854 854 with display_trap:
855 855 self.pdb.reset()
856 856 # Find the right frame so we don't pop up inside ipython itself
857 if hasattr(self,'tb'):
857 if hasattr(self,'tb') and self.tb is not None:
858 858 etb = self.tb
859 859 else:
860 860 etb = self.tb = sys.last_traceback
861 while self.tb.tb_next is not None:
861 while self.tb is not None and self.tb.tb_next is not None:
862 862 self.tb = self.tb.tb_next
863 863 if etb and etb.tb_next:
864 864 etb = etb.tb_next
865 865 self.pdb.botframe = etb.tb_frame
866 866 self.pdb.interaction(self.tb.tb_frame, self.tb)
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