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