##// END OF EJS Templates
- Fix exception name printing for Python 2.5.
fperez -
Show More

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

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