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