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