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