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