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