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