##// END OF EJS Templates
flush stdout/err before printing tracebacks
fperez -
Show More

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

@@ -1,897 +1,903 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ultraTB.py -- Spice up your tracebacks!
4 4
5 5 * ColorTB
6 6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 7 ColorTB class is a solution to that problem. It colors the different parts of a
8 8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 9 text editor.
10 10
11 11 Installation instructions for ColorTB:
12 12 import sys,ultraTB
13 13 sys.excepthook = ultraTB.ColorTB()
14 14
15 15 * VerboseTB
16 16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 18 and intended it for CGI programmers, but why should they have all the fun? I
19 19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 20 but kind of neat, and maybe useful for long-running programs that you believe
21 21 are bug-free. If a crash *does* occur in that type of program you want details.
22 22 Give it a shot--you'll love it or you'll hate it.
23 23
24 24 Note:
25 25
26 26 The Verbose mode prints the variables currently visible where the exception
27 27 happened (shortening their strings if too long). This can potentially be
28 28 very slow, if you happen to have a huge data structure whose string
29 29 representation is complex to compute. Your computer may appear to freeze for
30 30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 31 with Ctrl-C (maybe hitting it more than once).
32 32
33 33 If you encounter this kind of situation often, you may want to use the
34 34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 35 variables (but otherwise includes the information and context given by
36 36 Verbose).
37 37
38 38
39 39 Installation instructions for ColorTB:
40 40 import sys,ultraTB
41 41 sys.excepthook = ultraTB.VerboseTB()
42 42
43 43 Note: Much of the code in this module was lifted verbatim from the standard
44 44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45 45
46 46 * Color schemes
47 47 The colors are defined in the class TBTools through the use of the
48 48 ColorSchemeTable class. Currently the following exist:
49 49
50 50 - NoColor: allows all of this module to be used in any terminal (the color
51 51 escapes are just dummy blank strings).
52 52
53 53 - Linux: is meant to look good in a terminal like the Linux console (black
54 54 or very dark background).
55 55
56 56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 57 in light background terminals.
58 58
59 59 You can implement other color schemes easily, the syntax is fairly
60 60 self-explanatory. Please send back new schemes you develop to the author for
61 61 possible inclusion in future releases.
62 62
63 $Id: ultraTB.py 1956 2006-11-30 05:22:31Z fperez $"""
63 $Id: ultraTB.py 2027 2007-01-19 00:55:09Z fperez $"""
64 64
65 65 #*****************************************************************************
66 66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
67 67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
68 68 #
69 69 # Distributed under the terms of the BSD License. The full license is in
70 70 # the file COPYING, distributed as part of this software.
71 71 #*****************************************************************************
72 72
73 73 from IPython import Release
74 74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
75 75 Release.authors['Fernando'])
76 76 __license__ = Release.license
77 77
78 78 # Required modules
79 79 import inspect
80 80 import keyword
81 81 import linecache
82 82 import os
83 83 import pydoc
84 84 import string
85 85 import sys
86 86 import time
87 87 import tokenize
88 88 import traceback
89 89 import types
90 90
91 91 # IPython's own modules
92 92 # Modified pdb which doesn't damage IPython's readline handling
93 93 from IPython import Debugger
94 94 from IPython.ipstruct import Struct
95 95 from IPython.excolors import ExceptionColors
96 96 from IPython.genutils import Term,uniq_stable,error,info
97 97
98 98 # Globals
99 99 # amount of space to put line numbers before verbose tracebacks
100 100 INDENT_SIZE = 8
101 101
102 102 #---------------------------------------------------------------------------
103 103 # Code begins
104 104
105 105 # Utility functions
106 106 def inspect_error():
107 107 """Print a message about internal inspect errors.
108 108
109 109 These are unfortunately quite common."""
110 110
111 111 error('Internal Python error in the inspect module.\n'
112 112 'Below is the traceback from this internal error.\n')
113 113
114 114 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
115 115 import linecache
116 116 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
117 117
118 118 records = inspect.getinnerframes(etb, context)
119 119
120 120 # If the error is at the console, don't build any context, since it would
121 121 # otherwise produce 5 blank lines printed out (there is no file at the
122 122 # console)
123 123 rec_check = records[tb_offset:]
124 124 try:
125 125 rname = rec_check[0][1]
126 126 if rname == '<ipython console>' or rname.endswith('<string>'):
127 127 return rec_check
128 128 except IndexError:
129 129 pass
130 130
131 131 aux = traceback.extract_tb(etb)
132 132 assert len(records) == len(aux)
133 133 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
134 134 maybeStart = lnum-1 - context//2
135 135 start = max(maybeStart, 0)
136 136 end = start + context
137 137 lines = linecache.getlines(file)[start:end]
138 138 # pad with empty lines if necessary
139 139 if maybeStart < 0:
140 140 lines = (['\n'] * -maybeStart) + lines
141 141 if len(lines) < context:
142 142 lines += ['\n'] * (context - len(lines))
143 143 buf = list(records[i])
144 144 buf[LNUM_POS] = lnum
145 145 buf[INDEX_POS] = lnum - 1 - start
146 146 buf[LINES_POS] = lines
147 147 records[i] = tuple(buf)
148 148 return records[tb_offset:]
149 149
150 150 # Helper function -- largely belongs to VerboseTB, but we need the same
151 151 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
152 152 # can be recognized properly by ipython.el's py-traceback-line-re
153 153 # (SyntaxErrors have to be treated specially because they have no traceback)
154 154 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None):
155 155 numbers_width = INDENT_SIZE - 1
156 156 res = []
157 157 i = lnum - index
158 158 for line in lines:
159 159 if i == lnum:
160 160 # This is the line with the error
161 161 pad = numbers_width - len(str(i))
162 162 if pad >= 3:
163 163 marker = '-'*(pad-3) + '-> '
164 164 elif pad == 2:
165 165 marker = '> '
166 166 elif pad == 1:
167 167 marker = '>'
168 168 else:
169 169 marker = ''
170 170 num = marker + str(i)
171 171 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
172 172 Colors.line, line, Colors.Normal)
173 173 else:
174 174 num = '%*s' % (numbers_width,i)
175 175 line = '%s%s%s %s' %(Colors.lineno, num,
176 176 Colors.Normal, line)
177 177
178 178 res.append(line)
179 179 if lvals and i == lnum:
180 180 res.append(lvals + '\n')
181 181 i = i + 1
182 182 return res
183 183
184 184 #---------------------------------------------------------------------------
185 185 # Module classes
186 186 class TBTools:
187 187 """Basic tools used by all traceback printer classes."""
188 188
189 189 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
190 190 # Whether to call the interactive pdb debugger after printing
191 191 # tracebacks or not
192 192 self.call_pdb = call_pdb
193 193
194 194 # Create color table
195 195 self.color_scheme_table = ExceptionColors
196 196
197 197 self.set_colors(color_scheme)
198 198 self.old_scheme = color_scheme # save initial value for toggles
199 199
200 200 if call_pdb:
201 201 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
202 202 else:
203 203 self.pdb = None
204 204
205 205 def set_colors(self,*args,**kw):
206 206 """Shorthand access to the color table scheme selector method."""
207 207
208 208 # Set own color table
209 209 self.color_scheme_table.set_active_scheme(*args,**kw)
210 210 # for convenience, set Colors to the active scheme
211 211 self.Colors = self.color_scheme_table.active_colors
212 212 # Also set colors of debugger
213 213 if hasattr(self,'pdb') and self.pdb is not None:
214 214 self.pdb.set_colors(*args,**kw)
215 215
216 216 def color_toggle(self):
217 217 """Toggle between the currently active color scheme and NoColor."""
218 218
219 219 if self.color_scheme_table.active_scheme_name == 'NoColor':
220 220 self.color_scheme_table.set_active_scheme(self.old_scheme)
221 221 self.Colors = self.color_scheme_table.active_colors
222 222 else:
223 223 self.old_scheme = self.color_scheme_table.active_scheme_name
224 224 self.color_scheme_table.set_active_scheme('NoColor')
225 225 self.Colors = self.color_scheme_table.active_colors
226 226
227 227 #---------------------------------------------------------------------------
228 228 class ListTB(TBTools):
229 229 """Print traceback information from a traceback list, with optional color.
230 230
231 231 Calling: requires 3 arguments:
232 232 (etype, evalue, elist)
233 233 as would be obtained by:
234 234 etype, evalue, tb = sys.exc_info()
235 235 if tb:
236 236 elist = traceback.extract_tb(tb)
237 237 else:
238 238 elist = None
239 239
240 240 It can thus be used by programs which need to process the traceback before
241 241 printing (such as console replacements based on the code module from the
242 242 standard library).
243 243
244 244 Because they are meant to be called without a full traceback (only a
245 245 list), instances of this class can't call the interactive pdb debugger."""
246 246
247 247 def __init__(self,color_scheme = 'NoColor'):
248 248 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
249 249
250 250 def __call__(self, etype, value, elist):
251 Term.cout.flush()
252 Term.cerr.flush()
251 253 print >> Term.cerr, self.text(etype,value,elist)
252 254
253 255 def text(self,etype, value, elist,context=5):
254 256 """Return a color formatted string with the traceback info."""
255 257
256 258 Colors = self.Colors
257 259 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
258 260 if elist:
259 261 out_string.append('Traceback %s(most recent call last)%s:' % \
260 262 (Colors.normalEm, Colors.Normal) + '\n')
261 263 out_string.extend(self._format_list(elist))
262 264 lines = self._format_exception_only(etype, value)
263 265 for line in lines[:-1]:
264 266 out_string.append(" "+line)
265 267 out_string.append(lines[-1])
266 268 return ''.join(out_string)
267 269
268 270 def _format_list(self, extracted_list):
269 271 """Format a list of traceback entry tuples for printing.
270 272
271 273 Given a list of tuples as returned by extract_tb() or
272 274 extract_stack(), return a list of strings ready for printing.
273 275 Each string in the resulting list corresponds to the item with the
274 276 same index in the argument list. Each string ends in a newline;
275 277 the strings may contain internal newlines as well, for those items
276 278 whose source text line is not None.
277 279
278 280 Lifted almost verbatim from traceback.py
279 281 """
280 282
281 283 Colors = self.Colors
282 284 list = []
283 285 for filename, lineno, name, line in extracted_list[:-1]:
284 286 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
285 287 (Colors.filename, filename, Colors.Normal,
286 288 Colors.lineno, lineno, Colors.Normal,
287 289 Colors.name, name, Colors.Normal)
288 290 if line:
289 291 item = item + ' %s\n' % line.strip()
290 292 list.append(item)
291 293 # Emphasize the last entry
292 294 filename, lineno, name, line = extracted_list[-1]
293 295 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
294 296 (Colors.normalEm,
295 297 Colors.filenameEm, filename, Colors.normalEm,
296 298 Colors.linenoEm, lineno, Colors.normalEm,
297 299 Colors.nameEm, name, Colors.normalEm,
298 300 Colors.Normal)
299 301 if line:
300 302 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
301 303 Colors.Normal)
302 304 list.append(item)
303 305 return list
304 306
305 307 def _format_exception_only(self, etype, value):
306 308 """Format the exception part of a traceback.
307 309
308 310 The arguments are the exception type and value such as given by
309 311 sys.exc_info()[:2]. The return value is a list of strings, each ending
310 312 in a newline. Normally, the list contains a single string; however,
311 313 for SyntaxError exceptions, it contains several lines that (when
312 314 printed) display detailed information about where the syntax error
313 315 occurred. The message indicating which exception occurred is the
314 316 always last string in the list.
315 317
316 318 Also lifted nearly verbatim from traceback.py
317 319 """
318 320
319 321 Colors = self.Colors
320 322 list = []
321 323 if type(etype) == types.ClassType:
322 324 stype = Colors.excName + etype.__name__ + Colors.Normal
323 325 else:
324 326 stype = etype # String exceptions don't get special coloring
325 327 if value is None:
326 328 list.append( str(stype) + '\n')
327 329 else:
328 330 if etype is SyntaxError:
329 331 try:
330 332 msg, (filename, lineno, offset, line) = value
331 333 except:
332 334 pass
333 335 else:
334 336 #print 'filename is',filename # dbg
335 337 if not filename: filename = "<string>"
336 338 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
337 339 (Colors.normalEm,
338 340 Colors.filenameEm, filename, Colors.normalEm,
339 341 Colors.linenoEm, lineno, Colors.Normal ))
340 342 if line is not None:
341 343 i = 0
342 344 while i < len(line) and line[i].isspace():
343 345 i = i+1
344 346 list.append('%s %s%s\n' % (Colors.line,
345 347 line.strip(),
346 348 Colors.Normal))
347 349 if offset is not None:
348 350 s = ' '
349 351 for c in line[i:offset-1]:
350 352 if c.isspace():
351 353 s = s + c
352 354 else:
353 355 s = s + ' '
354 356 list.append('%s%s^%s\n' % (Colors.caret, s,
355 357 Colors.Normal) )
356 358 value = msg
357 359 s = self._some_str(value)
358 360 if s:
359 361 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
360 362 Colors.Normal, s))
361 363 else:
362 364 list.append('%s\n' % str(stype))
363 365 return list
364 366
365 367 def _some_str(self, value):
366 368 # Lifted from traceback.py
367 369 try:
368 370 return str(value)
369 371 except:
370 372 return '<unprintable %s object>' % type(value).__name__
371 373
372 374 #----------------------------------------------------------------------------
373 375 class VerboseTB(TBTools):
374 376 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
375 377 of HTML. Requires inspect and pydoc. Crazy, man.
376 378
377 379 Modified version which optionally strips the topmost entries from the
378 380 traceback, to be used with alternate interpreters (because their own code
379 381 would appear in the traceback)."""
380 382
381 383 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
382 384 call_pdb = 0, include_vars=1):
383 385 """Specify traceback offset, headers and color scheme.
384 386
385 387 Define how many frames to drop from the tracebacks. Calling it with
386 388 tb_offset=1 allows use of this handler in interpreters which will have
387 389 their own code at the top of the traceback (VerboseTB will first
388 390 remove that frame before printing the traceback info)."""
389 391 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
390 392 self.tb_offset = tb_offset
391 393 self.long_header = long_header
392 394 self.include_vars = include_vars
393 395
394 396 def text(self, etype, evalue, etb, context=5):
395 397 """Return a nice text document describing the traceback."""
396 398
397 399 # some locals
398 400 Colors = self.Colors # just a shorthand + quicker name lookup
399 401 ColorsNormal = Colors.Normal # used a lot
400 402 indent = ' '*INDENT_SIZE
401 403 exc = '%s%s%s' % (Colors.excName, str(etype), ColorsNormal)
402 404 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
403 405 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
404 406
405 407 # some internal-use functions
406 408 def text_repr(value):
407 409 """Hopefully pretty robust repr equivalent."""
408 410 # this is pretty horrible but should always return *something*
409 411 try:
410 412 return pydoc.text.repr(value)
411 413 except KeyboardInterrupt:
412 414 raise
413 415 except:
414 416 try:
415 417 return repr(value)
416 418 except KeyboardInterrupt:
417 419 raise
418 420 except:
419 421 try:
420 422 # all still in an except block so we catch
421 423 # getattr raising
422 424 name = getattr(value, '__name__', None)
423 425 if name:
424 426 # ick, recursion
425 427 return text_repr(name)
426 428 klass = getattr(value, '__class__', None)
427 429 if klass:
428 430 return '%s instance' % text_repr(klass)
429 431 except KeyboardInterrupt:
430 432 raise
431 433 except:
432 434 return 'UNRECOVERABLE REPR FAILURE'
433 435 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
434 436 def nullrepr(value, repr=text_repr): return ''
435 437
436 438 # meat of the code begins
437 439 if type(etype) is types.ClassType:
438 440 etype = etype.__name__
439 441
440 442 if self.long_header:
441 443 # Header with the exception type, python version, and date
442 444 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
443 445 date = time.ctime(time.time())
444 446
445 447 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
446 448 exc, ' '*(75-len(str(etype))-len(pyver)),
447 449 pyver, string.rjust(date, 75) )
448 450 head += "\nA problem occured executing Python code. Here is the sequence of function"\
449 451 "\ncalls leading up to the error, with the most recent (innermost) call last."
450 452 else:
451 453 # Simplified header
452 454 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
453 455 string.rjust('Traceback (most recent call last)',
454 456 75 - len(str(etype)) ) )
455 457 frames = []
456 458 # Flush cache before calling inspect. This helps alleviate some of the
457 459 # problems with python 2.3's inspect.py.
458 460 linecache.checkcache()
459 461 # Drop topmost frames if requested
460 462 try:
461 463 # Try the default getinnerframes and Alex's: Alex's fixes some
462 464 # problems, but it generates empty tracebacks for console errors
463 465 # (5 blanks lines) where none should be returned.
464 466 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
465 467 #print 'python records:', records # dbg
466 468 records = _fixed_getinnerframes(etb, context,self.tb_offset)
467 469 #print 'alex records:', records # dbg
468 470 except:
469 471
470 472 # FIXME: I've been getting many crash reports from python 2.3
471 473 # users, traceable to inspect.py. If I can find a small test-case
472 474 # to reproduce this, I should either write a better workaround or
473 475 # file a bug report against inspect (if that's the real problem).
474 476 # So far, I haven't been able to find an isolated example to
475 477 # reproduce the problem.
476 478 inspect_error()
477 479 traceback.print_exc(file=Term.cerr)
478 480 info('\nUnfortunately, your original traceback can not be constructed.\n')
479 481 return ''
480 482
481 483 # build some color string templates outside these nested loops
482 484 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
483 485 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
484 486 ColorsNormal)
485 487 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
486 488 (Colors.vName, Colors.valEm, ColorsNormal)
487 489 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
488 490 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
489 491 Colors.vName, ColorsNormal)
490 492 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
491 493 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
492 494 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
493 495 ColorsNormal)
494 496
495 497 # now, loop over all records printing context and info
496 498 abspath = os.path.abspath
497 499 for frame, file, lnum, func, lines, index in records:
498 500 #print '*** record:',file,lnum,func,lines,index # dbg
499 501 try:
500 502 file = file and abspath(file) or '?'
501 503 except OSError:
502 504 # if file is '<console>' or something not in the filesystem,
503 505 # the abspath call will throw an OSError. Just ignore it and
504 506 # keep the original file string.
505 507 pass
506 508 link = tpl_link % file
507 509 try:
508 510 args, varargs, varkw, locals = inspect.getargvalues(frame)
509 511 except:
510 512 # This can happen due to a bug in python2.3. We should be
511 513 # able to remove this try/except when 2.4 becomes a
512 514 # requirement. Bug details at http://python.org/sf/1005466
513 515 inspect_error()
514 516 traceback.print_exc(file=Term.cerr)
515 517 info("\nIPython's exception reporting continues...\n")
516 518
517 519 if func == '?':
518 520 call = ''
519 521 else:
520 522 # Decide whether to include variable details or not
521 523 var_repr = self.include_vars and eqrepr or nullrepr
522 524 try:
523 525 call = tpl_call % (func,inspect.formatargvalues(args,
524 526 varargs, varkw,
525 527 locals,formatvalue=var_repr))
526 528 except KeyError:
527 529 # Very odd crash from inspect.formatargvalues(). The
528 530 # scenario under which it appeared was a call to
529 531 # view(array,scale) in NumTut.view.view(), where scale had
530 532 # been defined as a scalar (it should be a tuple). Somehow
531 533 # inspect messes up resolving the argument list of view()
532 534 # and barfs out. At some point I should dig into this one
533 535 # and file a bug report about it.
534 536 inspect_error()
535 537 traceback.print_exc(file=Term.cerr)
536 538 info("\nIPython's exception reporting continues...\n")
537 539 call = tpl_call_fail % func
538 540
539 541 # Initialize a list of names on the current line, which the
540 542 # tokenizer below will populate.
541 543 names = []
542 544
543 545 def tokeneater(token_type, token, start, end, line):
544 546 """Stateful tokeneater which builds dotted names.
545 547
546 548 The list of names it appends to (from the enclosing scope) can
547 549 contain repeated composite names. This is unavoidable, since
548 550 there is no way to disambguate partial dotted structures until
549 551 the full list is known. The caller is responsible for pruning
550 552 the final list of duplicates before using it."""
551 553
552 554 # build composite names
553 555 if token == '.':
554 556 try:
555 557 names[-1] += '.'
556 558 # store state so the next token is added for x.y.z names
557 559 tokeneater.name_cont = True
558 560 return
559 561 except IndexError:
560 562 pass
561 563 if token_type == tokenize.NAME and token not in keyword.kwlist:
562 564 if tokeneater.name_cont:
563 565 # Dotted names
564 566 names[-1] += token
565 567 tokeneater.name_cont = False
566 568 else:
567 569 # Regular new names. We append everything, the caller
568 570 # will be responsible for pruning the list later. It's
569 571 # very tricky to try to prune as we go, b/c composite
570 572 # names can fool us. The pruning at the end is easy
571 573 # to do (or the caller can print a list with repeated
572 574 # names if so desired.
573 575 names.append(token)
574 576 elif token_type == tokenize.NEWLINE:
575 577 raise IndexError
576 578 # we need to store a bit of state in the tokenizer to build
577 579 # dotted names
578 580 tokeneater.name_cont = False
579 581
580 582 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
581 583 line = getline(file, lnum[0])
582 584 lnum[0] += 1
583 585 return line
584 586
585 587 # Build the list of names on this line of code where the exception
586 588 # occurred.
587 589 try:
588 590 # This builds the names list in-place by capturing it from the
589 591 # enclosing scope.
590 592 tokenize.tokenize(linereader, tokeneater)
591 593 except IndexError:
592 594 # signals exit of tokenizer
593 595 pass
594 596 except tokenize.TokenError,msg:
595 597 _m = ("An unexpected error occurred while tokenizing input\n"
596 598 "The following traceback may be corrupted or invalid\n"
597 599 "The error message is: %s\n" % msg)
598 600 error(_m)
599 601
600 602 # prune names list of duplicates, but keep the right order
601 603 unique_names = uniq_stable(names)
602 604
603 605 # Start loop over vars
604 606 lvals = []
605 607 if self.include_vars:
606 608 for name_full in unique_names:
607 609 name_base = name_full.split('.',1)[0]
608 610 if name_base in frame.f_code.co_varnames:
609 611 if locals.has_key(name_base):
610 612 try:
611 613 value = repr(eval(name_full,locals))
612 614 except:
613 615 value = undefined
614 616 else:
615 617 value = undefined
616 618 name = tpl_local_var % name_full
617 619 else:
618 620 if frame.f_globals.has_key(name_base):
619 621 try:
620 622 value = repr(eval(name_full,frame.f_globals))
621 623 except:
622 624 value = undefined
623 625 else:
624 626 value = undefined
625 627 name = tpl_global_var % name_full
626 628 lvals.append(tpl_name_val % (name,value))
627 629 if lvals:
628 630 lvals = '%s%s' % (indent,em_normal.join(lvals))
629 631 else:
630 632 lvals = ''
631 633
632 634 level = '%s %s\n' % (link,call)
633 635
634 636 if index is None:
635 637 frames.append(level)
636 638 else:
637 639 frames.append('%s%s' % (level,''.join(
638 640 _formatTracebackLines(lnum,index,lines,self.Colors,lvals))))
639 641
640 642 # Get (safely) a string form of the exception info
641 643 try:
642 644 etype_str,evalue_str = map(str,(etype,evalue))
643 645 except:
644 646 # User exception is improperly defined.
645 647 etype,evalue = str,sys.exc_info()[:2]
646 648 etype_str,evalue_str = map(str,(etype,evalue))
647 649 # ... and format it
648 650 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
649 651 ColorsNormal, evalue_str)]
650 652 if type(evalue) is types.InstanceType:
651 653 try:
652 654 names = [w for w in dir(evalue) if isinstance(w, basestring)]
653 655 except:
654 656 # Every now and then, an object with funny inernals blows up
655 657 # when dir() is called on it. We do the best we can to report
656 658 # the problem and continue
657 659 _m = '%sException reporting error (object with broken dir())%s:'
658 660 exception.append(_m % (Colors.excName,ColorsNormal))
659 661 etype_str,evalue_str = map(str,sys.exc_info()[:2])
660 662 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
661 663 ColorsNormal, evalue_str))
662 664 names = []
663 665 for name in names:
664 666 value = text_repr(getattr(evalue, name))
665 667 exception.append('\n%s%s = %s' % (indent, name, value))
666 668 # return all our info assembled as a single string
667 669 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
668 670
669 671 def debugger(self,force=False):
670 672 """Call up the pdb debugger if desired, always clean up the tb
671 673 reference.
672 674
673 675 Keywords:
674 676
675 677 - force(False): by default, this routine checks the instance call_pdb
676 678 flag and does not actually invoke the debugger if the flag is false.
677 679 The 'force' option forces the debugger to activate even if the flag
678 680 is false.
679 681
680 682 If the call_pdb flag is set, the pdb interactive debugger is
681 683 invoked. In all cases, the self.tb reference to the current traceback
682 684 is deleted to prevent lingering references which hamper memory
683 685 management.
684 686
685 687 Note that each call to pdb() does an 'import readline', so if your app
686 688 requires a special setup for the readline completers, you'll have to
687 689 fix that by hand after invoking the exception handler."""
688 690
689 691 if force or self.call_pdb:
690 692 if self.pdb is None:
691 693 self.pdb = Debugger.Pdb(
692 694 self.color_scheme_table.active_scheme_name)
693 695 # the system displayhook may have changed, restore the original
694 696 # for pdb
695 697 dhook = sys.displayhook
696 698 sys.displayhook = sys.__displayhook__
697 699 self.pdb.reset()
698 700 # Find the right frame so we don't pop up inside ipython itself
699 701 if hasattr(self,'tb'):
700 702 etb = self.tb
701 703 else:
702 704 etb = self.tb = sys.last_traceback
703 705 while self.tb.tb_next is not None:
704 706 self.tb = self.tb.tb_next
705 707 try:
706 708 if etb and etb.tb_next:
707 709 etb = etb.tb_next
708 710 self.pdb.botframe = etb.tb_frame
709 711 self.pdb.interaction(self.tb.tb_frame, self.tb)
710 712 finally:
711 713 sys.displayhook = dhook
712 714
713 715 if hasattr(self,'tb'):
714 716 del self.tb
715 717
716 718 def handler(self, info=None):
717 719 (etype, evalue, etb) = info or sys.exc_info()
718 720 self.tb = etb
721 Term.cout.flush()
722 Term.cerr.flush()
719 723 print >> Term.cerr, self.text(etype, evalue, etb)
720 724
721 725 # Changed so an instance can just be called as VerboseTB_inst() and print
722 726 # out the right info on its own.
723 727 def __call__(self, etype=None, evalue=None, etb=None):
724 728 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
725 729 if etb is None:
726 730 self.handler()
727 731 else:
728 732 self.handler((etype, evalue, etb))
729 733 self.debugger()
730 734
731 735 #----------------------------------------------------------------------------
732 736 class FormattedTB(VerboseTB,ListTB):
733 737 """Subclass ListTB but allow calling with a traceback.
734 738
735 739 It can thus be used as a sys.excepthook for Python > 2.1.
736 740
737 741 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
738 742
739 743 Allows a tb_offset to be specified. This is useful for situations where
740 744 one needs to remove a number of topmost frames from the traceback (such as
741 745 occurs with python programs that themselves execute other python code,
742 746 like Python shells). """
743 747
744 748 def __init__(self, mode = 'Plain', color_scheme='Linux',
745 749 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
746 750
747 751 # NEVER change the order of this list. Put new modes at the end:
748 752 self.valid_modes = ['Plain','Context','Verbose']
749 753 self.verbose_modes = self.valid_modes[1:3]
750 754
751 755 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
752 756 call_pdb=call_pdb,include_vars=include_vars)
753 757 self.set_mode(mode)
754 758
755 759 def _extract_tb(self,tb):
756 760 if tb:
757 761 return traceback.extract_tb(tb)
758 762 else:
759 763 return None
760 764
761 765 def text(self, etype, value, tb,context=5,mode=None):
762 766 """Return formatted traceback.
763 767
764 768 If the optional mode parameter is given, it overrides the current
765 769 mode."""
766 770
767 771 if mode is None:
768 772 mode = self.mode
769 773 if mode in self.verbose_modes:
770 774 # verbose modes need a full traceback
771 775 return VerboseTB.text(self,etype, value, tb,context=5)
772 776 else:
773 777 # We must check the source cache because otherwise we can print
774 778 # out-of-date source code.
775 779 linecache.checkcache()
776 780 # Now we can extract and format the exception
777 781 elist = self._extract_tb(tb)
778 782 if len(elist) > self.tb_offset:
779 783 del elist[:self.tb_offset]
780 784 return ListTB.text(self,etype,value,elist)
781 785
782 786 def set_mode(self,mode=None):
783 787 """Switch to the desired mode.
784 788
785 789 If mode is not specified, cycles through the available modes."""
786 790
787 791 if not mode:
788 792 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
789 793 len(self.valid_modes)
790 794 self.mode = self.valid_modes[new_idx]
791 795 elif mode not in self.valid_modes:
792 796 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
793 797 'Valid modes: '+str(self.valid_modes)
794 798 else:
795 799 self.mode = mode
796 800 # include variable details only in 'Verbose' mode
797 801 self.include_vars = (self.mode == self.valid_modes[2])
798 802
799 803 # some convenient shorcuts
800 804 def plain(self):
801 805 self.set_mode(self.valid_modes[0])
802 806
803 807 def context(self):
804 808 self.set_mode(self.valid_modes[1])
805 809
806 810 def verbose(self):
807 811 self.set_mode(self.valid_modes[2])
808 812
809 813 #----------------------------------------------------------------------------
810 814 class AutoFormattedTB(FormattedTB):
811 815 """A traceback printer which can be called on the fly.
812 816
813 817 It will find out about exceptions by itself.
814 818
815 819 A brief example:
816 820
817 821 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
818 822 try:
819 823 ...
820 824 except:
821 825 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
822 826 """
823 827 def __call__(self,etype=None,evalue=None,etb=None,
824 828 out=None,tb_offset=None):
825 829 """Print out a formatted exception traceback.
826 830
827 831 Optional arguments:
828 832 - out: an open file-like object to direct output to.
829 833
830 834 - tb_offset: the number of frames to skip over in the stack, on a
831 835 per-call basis (this overrides temporarily the instance's tb_offset
832 836 given at initialization time. """
833 837
834 838 if out is None:
835 839 out = Term.cerr
840 Term.cout.flush()
841 out.flush()
836 842 if tb_offset is not None:
837 843 tb_offset, self.tb_offset = self.tb_offset, tb_offset
838 844 print >> out, self.text(etype, evalue, etb)
839 845 self.tb_offset = tb_offset
840 846 else:
841 847 print >> out, self.text(etype, evalue, etb)
842 848 self.debugger()
843 849
844 850 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
845 851 if etype is None:
846 852 etype,value,tb = sys.exc_info()
847 853 self.tb = tb
848 854 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
849 855
850 856 #---------------------------------------------------------------------------
851 857 # A simple class to preserve Nathan's original functionality.
852 858 class ColorTB(FormattedTB):
853 859 """Shorthand to initialize a FormattedTB in Linux colors mode."""
854 860 def __init__(self,color_scheme='Linux',call_pdb=0):
855 861 FormattedTB.__init__(self,color_scheme=color_scheme,
856 862 call_pdb=call_pdb)
857 863
858 864 #----------------------------------------------------------------------------
859 865 # module testing (minimal)
860 866 if __name__ == "__main__":
861 867 def spam(c, (d, e)):
862 868 x = c + d
863 869 y = c * d
864 870 foo(x, y)
865 871
866 872 def foo(a, b, bar=1):
867 873 eggs(a, b + bar)
868 874
869 875 def eggs(f, g, z=globals()):
870 876 h = f + g
871 877 i = f - g
872 878 return h / i
873 879
874 880 print ''
875 881 print '*** Before ***'
876 882 try:
877 883 print spam(1, (2, 3))
878 884 except:
879 885 traceback.print_exc()
880 886 print ''
881 887
882 888 handler = ColorTB()
883 889 print '*** ColorTB ***'
884 890 try:
885 891 print spam(1, (2, 3))
886 892 except:
887 893 apply(handler, sys.exc_info() )
888 894 print ''
889 895
890 896 handler = VerboseTB()
891 897 print '*** VerboseTB ***'
892 898 try:
893 899 print spam(1, (2, 3))
894 900 except:
895 901 apply(handler, sys.exc_info() )
896 902 print ''
897 903
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now