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