##// END OF EJS Templates
Avoid calling getline() if lineno is None.
Jez Ng -
Show More
@@ -1,1238 +1,1242 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 unicode_literals
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 path as util_path
103 103 from IPython.utils import py3compat
104 104 from IPython.utils import pyfile
105 105 from IPython.utils import ulinecache
106 106 from IPython.utils.data import uniq_stable
107 107 from IPython.utils.openpy import read_py_file
108 108 from IPython.utils.warn import info, error
109 109
110 110 # Globals
111 111 # amount of space to put line numbers before verbose tracebacks
112 112 INDENT_SIZE = 8
113 113
114 114 # Default color scheme. This is used, for example, by the traceback
115 115 # formatter. When running in an actual IPython instance, the user's rc.colors
116 116 # value is used, but havinga module global makes this functionality available
117 117 # to users of ultratb who are NOT running inside ipython.
118 118 DEFAULT_SCHEME = 'NoColor'
119 119
120 120 #---------------------------------------------------------------------------
121 121 # Code begins
122 122
123 123 # Utility functions
124 124 def inspect_error():
125 125 """Print a message about internal inspect errors.
126 126
127 127 These are unfortunately quite common."""
128 128
129 129 error('Internal Python error in the inspect module.\n'
130 130 'Below is the traceback from this internal error.\n')
131 131
132 132 # This function is a monkeypatch we apply to the Python inspect module. We have
133 133 # now found when it's needed (see discussion on issue gh-1456), and we have a
134 134 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
135 135 # the monkeypatch is not applied. TK, Aug 2012.
136 136 def findsource(object):
137 137 """Return the entire source file and starting line number for an object.
138 138
139 139 The argument may be a module, class, method, function, traceback, frame,
140 140 or code object. The source code is returned as a list of all the lines
141 141 in the file and the line number indexes a line in that list. An IOError
142 142 is raised if the source code cannot be retrieved.
143 143
144 144 FIXED version with which we monkeypatch the stdlib to work around a bug."""
145 145
146 146 file = getsourcefile(object) or getfile(object)
147 147 # If the object is a frame, then trying to get the globals dict from its
148 148 # module won't work. Instead, the frame object itself has the globals
149 149 # dictionary.
150 150 globals_dict = None
151 151 if inspect.isframe(object):
152 152 # XXX: can this ever be false?
153 153 globals_dict = object.f_globals
154 154 else:
155 155 module = getmodule(object, file)
156 156 if module:
157 157 globals_dict = module.__dict__
158 158 lines = linecache.getlines(file, globals_dict)
159 159 if not lines:
160 160 raise IOError('could not get source code')
161 161
162 162 if ismodule(object):
163 163 return lines, 0
164 164
165 165 if isclass(object):
166 166 name = object.__name__
167 167 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
168 168 # make some effort to find the best matching class definition:
169 169 # use the one with the least indentation, which is the one
170 170 # that's most probably not inside a function definition.
171 171 candidates = []
172 172 for i in range(len(lines)):
173 173 match = pat.match(lines[i])
174 174 if match:
175 175 # if it's at toplevel, it's already the best one
176 176 if lines[i][0] == 'c':
177 177 return lines, i
178 178 # else add whitespace to candidate list
179 179 candidates.append((match.group(1), i))
180 180 if candidates:
181 181 # this will sort by whitespace, and by line number,
182 182 # less whitespace first
183 183 candidates.sort()
184 184 return lines, candidates[0][1]
185 185 else:
186 186 raise IOError('could not find class definition')
187 187
188 188 if ismethod(object):
189 189 object = object.im_func
190 190 if isfunction(object):
191 191 object = object.func_code
192 192 if istraceback(object):
193 193 object = object.tb_frame
194 194 if isframe(object):
195 195 object = object.f_code
196 196 if iscode(object):
197 197 if not hasattr(object, 'co_firstlineno'):
198 198 raise IOError('could not find function definition')
199 199 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
200 200 pmatch = pat.match
201 201 # fperez - fix: sometimes, co_firstlineno can give a number larger than
202 202 # the length of lines, which causes an error. Safeguard against that.
203 203 lnum = min(object.co_firstlineno,len(lines))-1
204 204 while lnum > 0:
205 205 if pmatch(lines[lnum]): break
206 206 lnum -= 1
207 207
208 208 return lines, lnum
209 209 raise IOError('could not find code object')
210 210
211 211 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
212 212 inspect.findsource = findsource
213 213
214 214 def fix_frame_records_filenames(records):
215 215 """Try to fix the filenames in each record from inspect.getinnerframes().
216 216
217 217 Particularly, modules loaded from within zip files have useless filenames
218 218 attached to their code object, and inspect.getinnerframes() just uses it.
219 219 """
220 220 fixed_records = []
221 221 for frame, filename, line_no, func_name, lines, index in records:
222 222 # Look inside the frame's globals dictionary for __file__, which should
223 223 # be better.
224 224 better_fn = frame.f_globals.get('__file__', None)
225 225 if isinstance(better_fn, str):
226 226 # Check the type just in case someone did something weird with
227 227 # __file__. It might also be None if the error occurred during
228 228 # import.
229 229 filename = better_fn
230 230 fixed_records.append((frame, filename, line_no, func_name, lines, index))
231 231 return fixed_records
232 232
233 233
234 234 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
235 235 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
236 236
237 237 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
238 238
239 239 # If the error is at the console, don't build any context, since it would
240 240 # otherwise produce 5 blank lines printed out (there is no file at the
241 241 # console)
242 242 rec_check = records[tb_offset:]
243 243 try:
244 244 rname = rec_check[0][1]
245 245 if rname == '<ipython console>' or rname.endswith('<string>'):
246 246 return rec_check
247 247 except IndexError:
248 248 pass
249 249
250 250 aux = traceback.extract_tb(etb)
251 251 assert len(records) == len(aux)
252 252 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
253 253 maybeStart = lnum-1 - context//2
254 254 start = max(maybeStart, 0)
255 255 end = start + context
256 256 lines = ulinecache.getlines(file)[start:end]
257 257 buf = list(records[i])
258 258 buf[LNUM_POS] = lnum
259 259 buf[INDEX_POS] = lnum - 1 - start
260 260 buf[LINES_POS] = lines
261 261 records[i] = tuple(buf)
262 262 return records[tb_offset:]
263 263
264 264 # Helper function -- largely belongs to VerboseTB, but we need the same
265 265 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
266 266 # can be recognized properly by ipython.el's py-traceback-line-re
267 267 # (SyntaxErrors have to be treated specially because they have no traceback)
268 268
269 269 _parser = PyColorize.Parser()
270 270
271 271 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
272 272 numbers_width = INDENT_SIZE - 1
273 273 res = []
274 274 i = lnum - index
275 275
276 276 # This lets us get fully syntax-highlighted tracebacks.
277 277 if scheme is None:
278 278 ipinst = ipapi.get()
279 279 if ipinst is not None:
280 280 scheme = ipinst.colors
281 281 else:
282 282 scheme = DEFAULT_SCHEME
283 283
284 284 _line_format = _parser.format2
285 285
286 286 for line in lines:
287 287 line = py3compat.cast_unicode(line)
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 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 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 have_filedata = False
548 548 Colors = self.Colors
549 549 list = []
550 550 stype = Colors.excName + etype.__name__ + Colors.Normal
551 551 if value is None:
552 552 # Not sure if this can still happen in Python 2.6 and above
553 553 list.append( py3compat.cast_unicode(stype) + '\n')
554 554 else:
555 555 if issubclass(etype, SyntaxError):
556 556 have_filedata = True
557 557 #print 'filename is',filename # dbg
558 558 if not value.filename: value.filename = "<string>"
559 if not value.lineno: value.lineno = "unknown"
559 if value.lineno:
560 lineno = value.lineno
561 textline = ulinecache.getline(value.filename, value.lineno)
562 else:
563 lineno = 'unknown'
564 textline = ''
560 565 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
561 566 (Colors.normalEm,
562 567 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
563 Colors.linenoEm, value.lineno, Colors.Normal ))
564 textline = ulinecache.getline(value.filename, value.lineno)
568 Colors.linenoEm, lineno, Colors.Normal ))
565 569 if textline == '':
566 570 textline = py3compat.cast_unicode(value.text, "utf-8")
567 571
568 572 if textline is not None:
569 573 i = 0
570 574 while i < len(textline) and textline[i].isspace():
571 575 i += 1
572 576 list.append('%s %s%s\n' % (Colors.line,
573 577 textline.strip(),
574 578 Colors.Normal))
575 579 if value.offset is not None:
576 580 s = ' '
577 581 for c in textline[i:value.offset-1]:
578 582 if c.isspace():
579 583 s += c
580 584 else:
581 585 s += ' '
582 586 list.append('%s%s^%s\n' % (Colors.caret, s,
583 587 Colors.Normal) )
584 588
585 589 try:
586 590 s = value.msg
587 591 except Exception:
588 592 s = self._some_str(value)
589 593 if s:
590 594 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
591 595 Colors.Normal, s))
592 596 else:
593 597 list.append('%s\n' % str(stype))
594 598
595 599 # sync with user hooks
596 600 if have_filedata:
597 601 ipinst = ipapi.get()
598 602 if ipinst is not None:
599 603 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
600 604
601 605 return list
602 606
603 607 def get_exception_only(self, etype, value):
604 608 """Only print the exception type and message, without a traceback.
605 609
606 610 Parameters
607 611 ----------
608 612 etype : exception type
609 613 value : exception value
610 614 """
611 615 return ListTB.structured_traceback(self, etype, value, [])
612 616
613 617
614 618 def show_exception_only(self, etype, evalue):
615 619 """Only print the exception type and message, without a traceback.
616 620
617 621 Parameters
618 622 ----------
619 623 etype : exception type
620 624 value : exception value
621 625 """
622 626 # This method needs to use __call__ from *this* class, not the one from
623 627 # a subclass whose signature or behavior may be different
624 628 ostream = self.ostream
625 629 ostream.flush()
626 630 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
627 631 ostream.flush()
628 632
629 633 def _some_str(self, value):
630 634 # Lifted from traceback.py
631 635 try:
632 636 return str(value)
633 637 except:
634 638 return '<unprintable %s object>' % type(value).__name__
635 639
636 640 #----------------------------------------------------------------------------
637 641 class VerboseTB(TBTools):
638 642 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
639 643 of HTML. Requires inspect and pydoc. Crazy, man.
640 644
641 645 Modified version which optionally strips the topmost entries from the
642 646 traceback, to be used with alternate interpreters (because their own code
643 647 would appear in the traceback)."""
644 648
645 649 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
646 650 tb_offset=0, long_header=False, include_vars=True,
647 651 check_cache=None):
648 652 """Specify traceback offset, headers and color scheme.
649 653
650 654 Define how many frames to drop from the tracebacks. Calling it with
651 655 tb_offset=1 allows use of this handler in interpreters which will have
652 656 their own code at the top of the traceback (VerboseTB will first
653 657 remove that frame before printing the traceback info)."""
654 658 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
655 659 ostream=ostream)
656 660 self.tb_offset = tb_offset
657 661 self.long_header = long_header
658 662 self.include_vars = include_vars
659 663 # By default we use linecache.checkcache, but the user can provide a
660 664 # different check_cache implementation. This is used by the IPython
661 665 # kernel to provide tracebacks for interactive code that is cached,
662 666 # by a compiler instance that flushes the linecache but preserves its
663 667 # own code cache.
664 668 if check_cache is None:
665 669 check_cache = linecache.checkcache
666 670 self.check_cache = check_cache
667 671
668 672 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
669 673 context=5):
670 674 """Return a nice text document describing the traceback."""
671 675
672 676 tb_offset = self.tb_offset if tb_offset is None else tb_offset
673 677
674 678 # some locals
675 679 try:
676 680 etype = etype.__name__
677 681 except AttributeError:
678 682 pass
679 683 Colors = self.Colors # just a shorthand + quicker name lookup
680 684 ColorsNormal = Colors.Normal # used a lot
681 685 col_scheme = self.color_scheme_table.active_scheme_name
682 686 indent = ' '*INDENT_SIZE
683 687 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
684 688 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
685 689 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
686 690
687 691 # some internal-use functions
688 692 def text_repr(value):
689 693 """Hopefully pretty robust repr equivalent."""
690 694 # this is pretty horrible but should always return *something*
691 695 try:
692 696 return pydoc.text.repr(value)
693 697 except KeyboardInterrupt:
694 698 raise
695 699 except:
696 700 try:
697 701 return repr(value)
698 702 except KeyboardInterrupt:
699 703 raise
700 704 except:
701 705 try:
702 706 # all still in an except block so we catch
703 707 # getattr raising
704 708 name = getattr(value, '__name__', None)
705 709 if name:
706 710 # ick, recursion
707 711 return text_repr(name)
708 712 klass = getattr(value, '__class__', None)
709 713 if klass:
710 714 return '%s instance' % text_repr(klass)
711 715 except KeyboardInterrupt:
712 716 raise
713 717 except:
714 718 return 'UNRECOVERABLE REPR FAILURE'
715 719 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
716 720 def nullrepr(value, repr=text_repr): return ''
717 721
718 722 # meat of the code begins
719 723 try:
720 724 etype = etype.__name__
721 725 except AttributeError:
722 726 pass
723 727
724 728 if self.long_header:
725 729 # Header with the exception type, python version, and date
726 730 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
727 731 date = time.ctime(time.time())
728 732
729 733 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
730 734 exc, ' '*(75-len(str(etype))-len(pyver)),
731 735 pyver, date.rjust(75) )
732 736 head += "\nA problem occured executing Python code. Here is the sequence of function"\
733 737 "\ncalls leading up to the error, with the most recent (innermost) call last."
734 738 else:
735 739 # Simplified header
736 740 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
737 741 'Traceback (most recent call last)'.\
738 742 rjust(75 - len(str(etype)) ) )
739 743 frames = []
740 744 # Flush cache before calling inspect. This helps alleviate some of the
741 745 # problems with python 2.3's inspect.py.
742 746 ##self.check_cache()
743 747 # Drop topmost frames if requested
744 748 try:
745 749 # Try the default getinnerframes and Alex's: Alex's fixes some
746 750 # problems, but it generates empty tracebacks for console errors
747 751 # (5 blanks lines) where none should be returned.
748 752 #records = inspect.getinnerframes(etb, context)[tb_offset:]
749 753 #print 'python records:', records # dbg
750 754 records = _fixed_getinnerframes(etb, context, tb_offset)
751 755 #print 'alex records:', records # dbg
752 756 except:
753 757
754 758 # FIXME: I've been getting many crash reports from python 2.3
755 759 # users, traceable to inspect.py. If I can find a small test-case
756 760 # to reproduce this, I should either write a better workaround or
757 761 # file a bug report against inspect (if that's the real problem).
758 762 # So far, I haven't been able to find an isolated example to
759 763 # reproduce the problem.
760 764 inspect_error()
761 765 traceback.print_exc(file=self.ostream)
762 766 info('\nUnfortunately, your original traceback can not be constructed.\n')
763 767 return ''
764 768
765 769 # build some color string templates outside these nested loops
766 770 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
767 771 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
768 772 ColorsNormal)
769 773 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
770 774 (Colors.vName, Colors.valEm, ColorsNormal)
771 775 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
772 776 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
773 777 Colors.vName, ColorsNormal)
774 778 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
775 779 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
776 780 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
777 781 ColorsNormal)
778 782
779 783 # now, loop over all records printing context and info
780 784 abspath = os.path.abspath
781 785 for frame, file, lnum, func, lines, index in records:
782 786 #print '*** record:',file,lnum,func,lines,index # dbg
783 787 if not file:
784 788 file = '?'
785 789 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
786 790 # Guess that filenames like <string> aren't real filenames, so
787 791 # don't call abspath on them.
788 792 try:
789 793 file = abspath(file)
790 794 except OSError:
791 795 # Not sure if this can still happen: abspath now works with
792 796 # file names like <string>
793 797 pass
794 798 file = py3compat.cast_unicode(file, util_path.fs_encoding)
795 799 link = tpl_link % file
796 800 args, varargs, varkw, locals = inspect.getargvalues(frame)
797 801
798 802 if func == '?':
799 803 call = ''
800 804 else:
801 805 # Decide whether to include variable details or not
802 806 var_repr = self.include_vars and eqrepr or nullrepr
803 807 try:
804 808 call = tpl_call % (func,inspect.formatargvalues(args,
805 809 varargs, varkw,
806 810 locals,formatvalue=var_repr))
807 811 except KeyError:
808 812 # This happens in situations like errors inside generator
809 813 # expressions, where local variables are listed in the
810 814 # line, but can't be extracted from the frame. I'm not
811 815 # 100% sure this isn't actually a bug in inspect itself,
812 816 # but since there's no info for us to compute with, the
813 817 # best we can do is report the failure and move on. Here
814 818 # we must *not* call any traceback construction again,
815 819 # because that would mess up use of %debug later on. So we
816 820 # simply report the failure and move on. The only
817 821 # limitation will be that this frame won't have locals
818 822 # listed in the call signature. Quite subtle problem...
819 823 # I can't think of a good way to validate this in a unit
820 824 # test, but running a script consisting of:
821 825 # dict( (k,v.strip()) for (k,v) in range(10) )
822 826 # will illustrate the error, if this exception catch is
823 827 # disabled.
824 828 call = tpl_call_fail % func
825 829
826 830 # Don't attempt to tokenize binary files.
827 831 if file.endswith(('.so', '.pyd', '.dll')):
828 832 frames.append('%s %s\n' % (link,call))
829 833 continue
830 834 elif file.endswith(('.pyc','.pyo')):
831 835 # Look up the corresponding source file.
832 836 file = pyfile.source_from_cache(file)
833 837
834 838 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
835 839 line = getline(file, lnum[0])
836 840 lnum[0] += 1
837 841 return line
838 842
839 843 # Build the list of names on this line of code where the exception
840 844 # occurred.
841 845 try:
842 846 names = []
843 847 name_cont = False
844 848
845 849 for token_type, token, start, end, line in generate_tokens(linereader):
846 850 # build composite names
847 851 if token_type == tokenize.NAME and token not in keyword.kwlist:
848 852 if name_cont:
849 853 # Continuation of a dotted name
850 854 try:
851 855 names[-1].append(token)
852 856 except IndexError:
853 857 names.append([token])
854 858 name_cont = False
855 859 else:
856 860 # Regular new names. We append everything, the caller
857 861 # will be responsible for pruning the list later. It's
858 862 # very tricky to try to prune as we go, b/c composite
859 863 # names can fool us. The pruning at the end is easy
860 864 # to do (or the caller can print a list with repeated
861 865 # names if so desired.
862 866 names.append([token])
863 867 elif token == '.':
864 868 name_cont = True
865 869 elif token_type == tokenize.NEWLINE:
866 870 break
867 871
868 872 except (IndexError, UnicodeDecodeError):
869 873 # signals exit of tokenizer
870 874 pass
871 875 except tokenize.TokenError as msg:
872 876 _m = ("An unexpected error occurred while tokenizing input\n"
873 877 "The following traceback may be corrupted or invalid\n"
874 878 "The error message is: %s\n" % msg)
875 879 error(_m)
876 880
877 881 # Join composite names (e.g. "dict.fromkeys")
878 882 names = ['.'.join(n) for n in names]
879 883 # prune names list of duplicates, but keep the right order
880 884 unique_names = uniq_stable(names)
881 885
882 886 # Start loop over vars
883 887 lvals = []
884 888 if self.include_vars:
885 889 for name_full in unique_names:
886 890 name_base = name_full.split('.',1)[0]
887 891 if name_base in frame.f_code.co_varnames:
888 892 if name_base in locals:
889 893 try:
890 894 value = repr(eval(name_full,locals))
891 895 except:
892 896 value = undefined
893 897 else:
894 898 value = undefined
895 899 name = tpl_local_var % name_full
896 900 else:
897 901 if name_base in frame.f_globals:
898 902 try:
899 903 value = repr(eval(name_full,frame.f_globals))
900 904 except:
901 905 value = undefined
902 906 else:
903 907 value = undefined
904 908 name = tpl_global_var % name_full
905 909 lvals.append(tpl_name_val % (name,value))
906 910 if lvals:
907 911 lvals = '%s%s' % (indent,em_normal.join(lvals))
908 912 else:
909 913 lvals = ''
910 914
911 915 level = '%s %s\n' % (link,call)
912 916
913 917 if index is None:
914 918 frames.append(level)
915 919 else:
916 920 frames.append('%s%s' % (level,''.join(
917 921 _format_traceback_lines(lnum,index,lines,Colors,lvals,
918 922 col_scheme))))
919 923
920 924 # Get (safely) a string form of the exception info
921 925 try:
922 926 etype_str,evalue_str = map(str,(etype,evalue))
923 927 except:
924 928 # User exception is improperly defined.
925 929 etype,evalue = str,sys.exc_info()[:2]
926 930 etype_str,evalue_str = map(str,(etype,evalue))
927 931 # ... and format it
928 932 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
929 933 ColorsNormal, py3compat.cast_unicode(evalue_str))]
930 934 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
931 935 try:
932 936 names = [w for w in dir(evalue) if isinstance(w, basestring)]
933 937 except:
934 938 # Every now and then, an object with funny inernals blows up
935 939 # when dir() is called on it. We do the best we can to report
936 940 # the problem and continue
937 941 _m = '%sException reporting error (object with broken dir())%s:'
938 942 exception.append(_m % (Colors.excName,ColorsNormal))
939 943 etype_str,evalue_str = map(str,sys.exc_info()[:2])
940 944 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
941 945 ColorsNormal, py3compat.cast_unicode(evalue_str)))
942 946 names = []
943 947 for name in names:
944 948 value = text_repr(getattr(evalue, name))
945 949 exception.append('\n%s%s = %s' % (indent, name, value))
946 950
947 951 # vds: >>
948 952 if records:
949 953 filepath, lnum = records[-1][1:3]
950 954 #print "file:", str(file), "linenb", str(lnum) # dbg
951 955 filepath = os.path.abspath(filepath)
952 956 ipinst = ipapi.get()
953 957 if ipinst is not None:
954 958 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
955 959 # vds: <<
956 960
957 961 # return all our info assembled as a single string
958 962 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
959 963 return [head] + frames + [''.join(exception[0])]
960 964
961 965 def debugger(self,force=False):
962 966 """Call up the pdb debugger if desired, always clean up the tb
963 967 reference.
964 968
965 969 Keywords:
966 970
967 971 - force(False): by default, this routine checks the instance call_pdb
968 972 flag and does not actually invoke the debugger if the flag is false.
969 973 The 'force' option forces the debugger to activate even if the flag
970 974 is false.
971 975
972 976 If the call_pdb flag is set, the pdb interactive debugger is
973 977 invoked. In all cases, the self.tb reference to the current traceback
974 978 is deleted to prevent lingering references which hamper memory
975 979 management.
976 980
977 981 Note that each call to pdb() does an 'import readline', so if your app
978 982 requires a special setup for the readline completers, you'll have to
979 983 fix that by hand after invoking the exception handler."""
980 984
981 985 if force or self.call_pdb:
982 986 if self.pdb is None:
983 987 self.pdb = debugger.Pdb(
984 988 self.color_scheme_table.active_scheme_name)
985 989 # the system displayhook may have changed, restore the original
986 990 # for pdb
987 991 display_trap = DisplayTrap(hook=sys.__displayhook__)
988 992 with display_trap:
989 993 self.pdb.reset()
990 994 # Find the right frame so we don't pop up inside ipython itself
991 995 if hasattr(self,'tb') and self.tb is not None:
992 996 etb = self.tb
993 997 else:
994 998 etb = self.tb = sys.last_traceback
995 999 while self.tb is not None and self.tb.tb_next is not None:
996 1000 self.tb = self.tb.tb_next
997 1001 if etb and etb.tb_next:
998 1002 etb = etb.tb_next
999 1003 self.pdb.botframe = etb.tb_frame
1000 1004 self.pdb.interaction(self.tb.tb_frame, self.tb)
1001 1005
1002 1006 if hasattr(self,'tb'):
1003 1007 del self.tb
1004 1008
1005 1009 def handler(self, info=None):
1006 1010 (etype, evalue, etb) = info or sys.exc_info()
1007 1011 self.tb = etb
1008 1012 ostream = self.ostream
1009 1013 ostream.flush()
1010 1014 ostream.write(self.text(etype, evalue, etb))
1011 1015 ostream.write('\n')
1012 1016 ostream.flush()
1013 1017
1014 1018 # Changed so an instance can just be called as VerboseTB_inst() and print
1015 1019 # out the right info on its own.
1016 1020 def __call__(self, etype=None, evalue=None, etb=None):
1017 1021 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1018 1022 if etb is None:
1019 1023 self.handler()
1020 1024 else:
1021 1025 self.handler((etype, evalue, etb))
1022 1026 try:
1023 1027 self.debugger()
1024 1028 except KeyboardInterrupt:
1025 1029 print "\nKeyboardInterrupt"
1026 1030
1027 1031 #----------------------------------------------------------------------------
1028 1032 class FormattedTB(VerboseTB, ListTB):
1029 1033 """Subclass ListTB but allow calling with a traceback.
1030 1034
1031 1035 It can thus be used as a sys.excepthook for Python > 2.1.
1032 1036
1033 1037 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1034 1038
1035 1039 Allows a tb_offset to be specified. This is useful for situations where
1036 1040 one needs to remove a number of topmost frames from the traceback (such as
1037 1041 occurs with python programs that themselves execute other python code,
1038 1042 like Python shells). """
1039 1043
1040 1044 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1041 1045 ostream=None,
1042 1046 tb_offset=0, long_header=False, include_vars=False,
1043 1047 check_cache=None):
1044 1048
1045 1049 # NEVER change the order of this list. Put new modes at the end:
1046 1050 self.valid_modes = ['Plain','Context','Verbose']
1047 1051 self.verbose_modes = self.valid_modes[1:3]
1048 1052
1049 1053 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1050 1054 ostream=ostream, tb_offset=tb_offset,
1051 1055 long_header=long_header, include_vars=include_vars,
1052 1056 check_cache=check_cache)
1053 1057
1054 1058 # Different types of tracebacks are joined with different separators to
1055 1059 # form a single string. They are taken from this dict
1056 1060 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1057 1061 # set_mode also sets the tb_join_char attribute
1058 1062 self.set_mode(mode)
1059 1063
1060 1064 def _extract_tb(self,tb):
1061 1065 if tb:
1062 1066 return traceback.extract_tb(tb)
1063 1067 else:
1064 1068 return None
1065 1069
1066 1070 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1067 1071 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1068 1072 mode = self.mode
1069 1073 if mode in self.verbose_modes:
1070 1074 # Verbose modes need a full traceback
1071 1075 return VerboseTB.structured_traceback(
1072 1076 self, etype, value, tb, tb_offset, context
1073 1077 )
1074 1078 else:
1075 1079 # We must check the source cache because otherwise we can print
1076 1080 # out-of-date source code.
1077 1081 self.check_cache()
1078 1082 # Now we can extract and format the exception
1079 1083 elist = self._extract_tb(tb)
1080 1084 return ListTB.structured_traceback(
1081 1085 self, etype, value, elist, tb_offset, context
1082 1086 )
1083 1087
1084 1088 def stb2text(self, stb):
1085 1089 """Convert a structured traceback (a list) to a string."""
1086 1090 return self.tb_join_char.join(stb)
1087 1091
1088 1092
1089 1093 def set_mode(self,mode=None):
1090 1094 """Switch to the desired mode.
1091 1095
1092 1096 If mode is not specified, cycles through the available modes."""
1093 1097
1094 1098 if not mode:
1095 1099 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1096 1100 len(self.valid_modes)
1097 1101 self.mode = self.valid_modes[new_idx]
1098 1102 elif mode not in self.valid_modes:
1099 1103 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1100 1104 'Valid modes: '+str(self.valid_modes))
1101 1105 else:
1102 1106 self.mode = mode
1103 1107 # include variable details only in 'Verbose' mode
1104 1108 self.include_vars = (self.mode == self.valid_modes[2])
1105 1109 # Set the join character for generating text tracebacks
1106 1110 self.tb_join_char = self._join_chars[self.mode]
1107 1111
1108 1112 # some convenient shorcuts
1109 1113 def plain(self):
1110 1114 self.set_mode(self.valid_modes[0])
1111 1115
1112 1116 def context(self):
1113 1117 self.set_mode(self.valid_modes[1])
1114 1118
1115 1119 def verbose(self):
1116 1120 self.set_mode(self.valid_modes[2])
1117 1121
1118 1122 #----------------------------------------------------------------------------
1119 1123 class AutoFormattedTB(FormattedTB):
1120 1124 """A traceback printer which can be called on the fly.
1121 1125
1122 1126 It will find out about exceptions by itself.
1123 1127
1124 1128 A brief example:
1125 1129
1126 1130 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1127 1131 try:
1128 1132 ...
1129 1133 except:
1130 1134 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1131 1135 """
1132 1136
1133 1137 def __call__(self,etype=None,evalue=None,etb=None,
1134 1138 out=None,tb_offset=None):
1135 1139 """Print out a formatted exception traceback.
1136 1140
1137 1141 Optional arguments:
1138 1142 - out: an open file-like object to direct output to.
1139 1143
1140 1144 - tb_offset: the number of frames to skip over in the stack, on a
1141 1145 per-call basis (this overrides temporarily the instance's tb_offset
1142 1146 given at initialization time. """
1143 1147
1144 1148
1145 1149 if out is None:
1146 1150 out = self.ostream
1147 1151 out.flush()
1148 1152 out.write(self.text(etype, evalue, etb, tb_offset))
1149 1153 out.write('\n')
1150 1154 out.flush()
1151 1155 # FIXME: we should remove the auto pdb behavior from here and leave
1152 1156 # that to the clients.
1153 1157 try:
1154 1158 self.debugger()
1155 1159 except KeyboardInterrupt:
1156 1160 print "\nKeyboardInterrupt"
1157 1161
1158 1162 def structured_traceback(self, etype=None, value=None, tb=None,
1159 1163 tb_offset=None, context=5):
1160 1164 if etype is None:
1161 1165 etype,value,tb = sys.exc_info()
1162 1166 self.tb = tb
1163 1167 return FormattedTB.structured_traceback(
1164 1168 self, etype, value, tb, tb_offset, context)
1165 1169
1166 1170 #---------------------------------------------------------------------------
1167 1171
1168 1172 # A simple class to preserve Nathan's original functionality.
1169 1173 class ColorTB(FormattedTB):
1170 1174 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1171 1175 def __init__(self,color_scheme='Linux',call_pdb=0):
1172 1176 FormattedTB.__init__(self,color_scheme=color_scheme,
1173 1177 call_pdb=call_pdb)
1174 1178
1175 1179
1176 1180 class SyntaxTB(ListTB):
1177 1181 """Extension which holds some state: the last exception value"""
1178 1182
1179 1183 def __init__(self,color_scheme = 'NoColor'):
1180 1184 ListTB.__init__(self,color_scheme)
1181 1185 self.last_syntax_error = None
1182 1186
1183 1187 def __call__(self, etype, value, elist):
1184 1188 self.last_syntax_error = value
1185 1189 ListTB.__call__(self,etype,value,elist)
1186 1190
1187 1191 def clear_err_state(self):
1188 1192 """Return the current error state and clear it"""
1189 1193 e = self.last_syntax_error
1190 1194 self.last_syntax_error = None
1191 1195 return e
1192 1196
1193 1197 def stb2text(self, stb):
1194 1198 """Convert a structured traceback (a list) to a string."""
1195 1199 return ''.join(stb)
1196 1200
1197 1201
1198 1202 #----------------------------------------------------------------------------
1199 1203 # module testing (minimal)
1200 1204 if __name__ == "__main__":
1201 1205 def spam(c, d_e):
1202 1206 (d, e) = d_e
1203 1207 x = c + d
1204 1208 y = c * d
1205 1209 foo(x, y)
1206 1210
1207 1211 def foo(a, b, bar=1):
1208 1212 eggs(a, b + bar)
1209 1213
1210 1214 def eggs(f, g, z=globals()):
1211 1215 h = f + g
1212 1216 i = f - g
1213 1217 return h / i
1214 1218
1215 1219 print ''
1216 1220 print '*** Before ***'
1217 1221 try:
1218 1222 print spam(1, (2, 3))
1219 1223 except:
1220 1224 traceback.print_exc()
1221 1225 print ''
1222 1226
1223 1227 handler = ColorTB()
1224 1228 print '*** ColorTB ***'
1225 1229 try:
1226 1230 print spam(1, (2, 3))
1227 1231 except:
1228 1232 handler(*sys.exc_info())
1229 1233 print ''
1230 1234
1231 1235 handler = VerboseTB()
1232 1236 print '*** VerboseTB ***'
1233 1237 try:
1234 1238 print spam(1, (2, 3))
1235 1239 except:
1236 1240 handler(*sys.exc_info())
1237 1241 print ''
1238 1242
General Comments 0
You need to be logged in to leave comments. Login now