##// END OF EJS Templates
Handle stackdata.RepeatedFrames
Alex Hall -
Show More
@@ -1,1057 +1,1062 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 44 potentially leak sensitive information like access keys, or unencrypted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 - Neutral: a neutral color scheme that should be readable on both light and
71 71 dark background
72 72
73 73 You can implement other color schemes easily, the syntax is fairly
74 74 self-explanatory. Please send back new schemes you develop to the author for
75 75 possible inclusion in future releases.
76 76
77 77 Inheritance diagram:
78 78
79 79 .. inheritance-diagram:: IPython.core.ultratb
80 80 :parts: 3
81 81 """
82 82
83 83 #*****************************************************************************
84 84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 86 #
87 87 # Distributed under the terms of the BSD License. The full license is in
88 88 # the file COPYING, distributed as part of this software.
89 89 #*****************************************************************************
90 90
91 91
92 92 import inspect
93 93 import linecache
94 94 import pydoc
95 95 import sys
96 96 import time
97 97 import tokenize
98 98 import traceback
99 99
100 100 import stack_data
101 101
102 102 try: # Python 2
103 103 generate_tokens = tokenize.generate_tokens
104 104 except AttributeError: # Python 3
105 105 generate_tokens = tokenize.tokenize
106 106
107 107 # IPython's own modules
108 108 from IPython import get_ipython
109 109 from IPython.core import debugger
110 110 from IPython.core.display_trap import DisplayTrap
111 111 from IPython.core.excolors import exception_colors
112 112 from IPython.utils import PyColorize
113 113 from IPython.utils import path as util_path
114 114 from IPython.utils import py3compat
115 115 from IPython.utils.terminal import get_terminal_size
116 116
117 117 import IPython.utils.colorable as colorable
118 118
119 119 # Globals
120 120 # amount of space to put line numbers before verbose tracebacks
121 121 INDENT_SIZE = 8
122 122
123 123 # Default color scheme. This is used, for example, by the traceback
124 124 # formatter. When running in an actual IPython instance, the user's rc.colors
125 125 # value is used, but having a module global makes this functionality available
126 126 # to users of ultratb who are NOT running inside ipython.
127 127 DEFAULT_SCHEME = 'NoColor'
128 128
129 129 # ---------------------------------------------------------------------------
130 130 # Code begins
131 131
132 132 # Helper function -- largely belongs to VerboseTB, but we need the same
133 133 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
134 134 # can be recognized properly by ipython.el's py-traceback-line-re
135 135 # (SyntaxErrors have to be treated specially because they have no traceback)
136 136
137 137
138 138 def _format_traceback_lines(lines, Colors, lvals, _line_format):
139 139 """
140 140 Format tracebacks lines with pointing arrow, leading numbers...
141 141
142 142 Parameters
143 143 ==========
144 144
145 145 lines: list[Line]
146 146 Colors:
147 147 ColorScheme used.
148 148 lvals: str
149 149 Values of local variables, already colored, to inject just after the error line.
150 150 _line_format: f (str) -> (str, bool)
151 151 return (colorized version of str, failure to do so)
152 152 """
153 153 numbers_width = INDENT_SIZE - 1
154 154 res = []
155 155
156 156 for stack_line in lines:
157 157 line = stack_line.text.rstrip('\n') + '\n'
158 158
159 159 new_line, err = _line_format(line, 'str')
160 160 if not err:
161 161 line = new_line
162 162
163 163 lineno = stack_line.lineno
164 164 if stack_line.is_current:
165 165 # This is the line with the error
166 166 pad = numbers_width - len(str(lineno))
167 167 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
168 168 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
169 169 Colors.line, line, Colors.Normal)
170 170 else:
171 171 num = '%*s' % (numbers_width, lineno)
172 172 line = '%s%s%s %s' % (Colors.lineno, num,
173 173 Colors.Normal, line)
174 174
175 175 res.append(line)
176 176 if lvals and stack_line.is_current:
177 177 res.append(lvals + '\n')
178 178 return res
179 179
180 180
181 181 #---------------------------------------------------------------------------
182 182 # Module classes
183 183 class TBTools(colorable.Colorable):
184 184 """Basic tools used by all traceback printer classes."""
185 185
186 186 # Number of frames to skip when reporting tracebacks
187 187 tb_offset = 0
188 188
189 189 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
190 190 # Whether to call the interactive pdb debugger after printing
191 191 # tracebacks or not
192 192 super(TBTools, self).__init__(parent=parent, config=config)
193 193 self.call_pdb = call_pdb
194 194
195 195 # Output stream to write to. Note that we store the original value in
196 196 # a private attribute and then make the public ostream a property, so
197 197 # that we can delay accessing sys.stdout until runtime. The way
198 198 # things are written now, the sys.stdout object is dynamically managed
199 199 # so a reference to it should NEVER be stored statically. This
200 200 # property approach confines this detail to a single location, and all
201 201 # subclasses can simply access self.ostream for writing.
202 202 self._ostream = ostream
203 203
204 204 # Create color table
205 205 self.color_scheme_table = exception_colors()
206 206
207 207 self.set_colors(color_scheme)
208 208 self.old_scheme = color_scheme # save initial value for toggles
209 209
210 210 if call_pdb:
211 211 self.pdb = debugger.Pdb()
212 212 else:
213 213 self.pdb = None
214 214
215 215 def _get_ostream(self):
216 216 """Output stream that exceptions are written to.
217 217
218 218 Valid values are:
219 219
220 220 - None: the default, which means that IPython will dynamically resolve
221 221 to sys.stdout. This ensures compatibility with most tools, including
222 222 Windows (where plain stdout doesn't recognize ANSI escapes).
223 223
224 224 - Any object with 'write' and 'flush' attributes.
225 225 """
226 226 return sys.stdout if self._ostream is None else self._ostream
227 227
228 228 def _set_ostream(self, val):
229 229 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
230 230 self._ostream = val
231 231
232 232 ostream = property(_get_ostream, _set_ostream)
233 233
234 234 def get_parts_of_chained_exception(self, evalue):
235 235 def get_chained_exception(exception_value):
236 236 cause = getattr(exception_value, '__cause__', None)
237 237 if cause:
238 238 return cause
239 239 if getattr(exception_value, '__suppress_context__', False):
240 240 return None
241 241 return getattr(exception_value, '__context__', None)
242 242
243 243 chained_evalue = get_chained_exception(evalue)
244 244
245 245 if chained_evalue:
246 246 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
247 247
248 248 def prepare_chained_exception_message(self, cause):
249 249 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
250 250 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
251 251
252 252 if cause:
253 253 message = [[direct_cause]]
254 254 else:
255 255 message = [[exception_during_handling]]
256 256 return message
257 257
258 258 def set_colors(self, *args, **kw):
259 259 """Shorthand access to the color table scheme selector method."""
260 260
261 261 # Set own color table
262 262 self.color_scheme_table.set_active_scheme(*args, **kw)
263 263 # for convenience, set Colors to the active scheme
264 264 self.Colors = self.color_scheme_table.active_colors
265 265 # Also set colors of debugger
266 266 if hasattr(self, 'pdb') and self.pdb is not None:
267 267 self.pdb.set_colors(*args, **kw)
268 268
269 269 def color_toggle(self):
270 270 """Toggle between the currently active color scheme and NoColor."""
271 271
272 272 if self.color_scheme_table.active_scheme_name == 'NoColor':
273 273 self.color_scheme_table.set_active_scheme(self.old_scheme)
274 274 self.Colors = self.color_scheme_table.active_colors
275 275 else:
276 276 self.old_scheme = self.color_scheme_table.active_scheme_name
277 277 self.color_scheme_table.set_active_scheme('NoColor')
278 278 self.Colors = self.color_scheme_table.active_colors
279 279
280 280 def stb2text(self, stb):
281 281 """Convert a structured traceback (a list) to a string."""
282 282 return '\n'.join(stb)
283 283
284 284 def text(self, etype, value, tb, tb_offset=None, context=5):
285 285 """Return formatted traceback.
286 286
287 287 Subclasses may override this if they add extra arguments.
288 288 """
289 289 tb_list = self.structured_traceback(etype, value, tb,
290 290 tb_offset, context)
291 291 return self.stb2text(tb_list)
292 292
293 293 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
294 294 context=5, mode=None):
295 295 """Return a list of traceback frames.
296 296
297 297 Must be implemented by each class.
298 298 """
299 299 raise NotImplementedError()
300 300
301 301
302 302 #---------------------------------------------------------------------------
303 303 class ListTB(TBTools):
304 304 """Print traceback information from a traceback list, with optional color.
305 305
306 306 Calling requires 3 arguments: (etype, evalue, elist)
307 307 as would be obtained by::
308 308
309 309 etype, evalue, tb = sys.exc_info()
310 310 if tb:
311 311 elist = traceback.extract_tb(tb)
312 312 else:
313 313 elist = None
314 314
315 315 It can thus be used by programs which need to process the traceback before
316 316 printing (such as console replacements based on the code module from the
317 317 standard library).
318 318
319 319 Because they are meant to be called without a full traceback (only a
320 320 list), instances of this class can't call the interactive pdb debugger."""
321 321
322 322 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
323 323 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
324 324 ostream=ostream, parent=parent,config=config)
325 325
326 326 def __call__(self, etype, value, elist):
327 327 self.ostream.flush()
328 328 self.ostream.write(self.text(etype, value, elist))
329 329 self.ostream.write('\n')
330 330
331 331 def _extract_tb(self, tb):
332 332 if tb:
333 333 return traceback.extract_tb(tb)
334 334 else:
335 335 return None
336 336
337 337 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
338 338 context=5):
339 339 """Return a color formatted string with the traceback info.
340 340
341 341 Parameters
342 342 ----------
343 343 etype : exception type
344 344 Type of the exception raised.
345 345
346 346 evalue : object
347 347 Data stored in the exception
348 348
349 349 etb : object
350 350 If list: List of frames, see class docstring for details.
351 351 If Traceback: Traceback of the exception.
352 352
353 353 tb_offset : int, optional
354 354 Number of frames in the traceback to skip. If not given, the
355 355 instance evalue is used (set in constructor).
356 356
357 357 context : int, optional
358 358 Number of lines of context information to print.
359 359
360 360 Returns
361 361 -------
362 362 String with formatted exception.
363 363 """
364 364 # This is a workaround to get chained_exc_ids in recursive calls
365 365 # etb should not be a tuple if structured_traceback is not recursive
366 366 if isinstance(etb, tuple):
367 367 etb, chained_exc_ids = etb
368 368 else:
369 369 chained_exc_ids = set()
370 370
371 371 if isinstance(etb, list):
372 372 elist = etb
373 373 elif etb is not None:
374 374 elist = self._extract_tb(etb)
375 375 else:
376 376 elist = []
377 377 tb_offset = self.tb_offset if tb_offset is None else tb_offset
378 378 Colors = self.Colors
379 379 out_list = []
380 380 if elist:
381 381
382 382 if tb_offset and len(elist) > tb_offset:
383 383 elist = elist[tb_offset:]
384 384
385 385 out_list.append('Traceback %s(most recent call last)%s:' %
386 386 (Colors.normalEm, Colors.Normal) + '\n')
387 387 out_list.extend(self._format_list(elist))
388 388 # The exception info should be a single entry in the list.
389 389 lines = ''.join(self._format_exception_only(etype, evalue))
390 390 out_list.append(lines)
391 391
392 392 exception = self.get_parts_of_chained_exception(evalue)
393 393
394 394 if exception and not id(exception[1]) in chained_exc_ids:
395 395 chained_exception_message = self.prepare_chained_exception_message(
396 396 evalue.__cause__)[0]
397 397 etype, evalue, etb = exception
398 398 # Trace exception to avoid infinite 'cause' loop
399 399 chained_exc_ids.add(id(exception[1]))
400 400 chained_exceptions_tb_offset = 0
401 401 out_list = (
402 402 self.structured_traceback(
403 403 etype, evalue, (etb, chained_exc_ids),
404 404 chained_exceptions_tb_offset, context)
405 405 + chained_exception_message
406 406 + out_list)
407 407
408 408 return out_list
409 409
410 410 def _format_list(self, extracted_list):
411 411 """Format a list of traceback entry tuples for printing.
412 412
413 413 Given a list of tuples as returned by extract_tb() or
414 414 extract_stack(), return a list of strings ready for printing.
415 415 Each string in the resulting list corresponds to the item with the
416 416 same index in the argument list. Each string ends in a newline;
417 417 the strings may contain internal newlines as well, for those items
418 418 whose source text line is not None.
419 419
420 420 Lifted almost verbatim from traceback.py
421 421 """
422 422
423 423 Colors = self.Colors
424 424 list = []
425 425 for filename, lineno, name, line in extracted_list[:-1]:
426 426 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
427 427 (Colors.filename, filename, Colors.Normal,
428 428 Colors.lineno, lineno, Colors.Normal,
429 429 Colors.name, name, Colors.Normal)
430 430 if line:
431 431 item += ' %s\n' % line.strip()
432 432 list.append(item)
433 433 # Emphasize the last entry
434 434 filename, lineno, name, line = extracted_list[-1]
435 435 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
436 436 (Colors.normalEm,
437 437 Colors.filenameEm, filename, Colors.normalEm,
438 438 Colors.linenoEm, lineno, Colors.normalEm,
439 439 Colors.nameEm, name, Colors.normalEm,
440 440 Colors.Normal)
441 441 if line:
442 442 item += '%s %s%s\n' % (Colors.line, line.strip(),
443 443 Colors.Normal)
444 444 list.append(item)
445 445 return list
446 446
447 447 def _format_exception_only(self, etype, value):
448 448 """Format the exception part of a traceback.
449 449
450 450 The arguments are the exception type and value such as given by
451 451 sys.exc_info()[:2]. The return value is a list of strings, each ending
452 452 in a newline. Normally, the list contains a single string; however,
453 453 for SyntaxError exceptions, it contains several lines that (when
454 454 printed) display detailed information about where the syntax error
455 455 occurred. The message indicating which exception occurred is the
456 456 always last string in the list.
457 457
458 458 Also lifted nearly verbatim from traceback.py
459 459 """
460 460 have_filedata = False
461 461 Colors = self.Colors
462 462 list = []
463 463 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
464 464 if value is None:
465 465 # Not sure if this can still happen in Python 2.6 and above
466 466 list.append(stype + '\n')
467 467 else:
468 468 if issubclass(etype, SyntaxError):
469 469 have_filedata = True
470 470 if not value.filename: value.filename = "<string>"
471 471 if value.lineno:
472 472 lineno = value.lineno
473 473 textline = linecache.getline(value.filename, value.lineno)
474 474 else:
475 475 lineno = 'unknown'
476 476 textline = ''
477 477 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
478 478 (Colors.normalEm,
479 479 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
480 480 Colors.linenoEm, lineno, Colors.Normal ))
481 481 if textline == '':
482 482 textline = py3compat.cast_unicode(value.text, "utf-8")
483 483
484 484 if textline is not None:
485 485 i = 0
486 486 while i < len(textline) and textline[i].isspace():
487 487 i += 1
488 488 list.append('%s %s%s\n' % (Colors.line,
489 489 textline.strip(),
490 490 Colors.Normal))
491 491 if value.offset is not None:
492 492 s = ' '
493 493 for c in textline[i:value.offset - 1]:
494 494 if c.isspace():
495 495 s += c
496 496 else:
497 497 s += ' '
498 498 list.append('%s%s^%s\n' % (Colors.caret, s,
499 499 Colors.Normal))
500 500
501 501 try:
502 502 s = value.msg
503 503 except Exception:
504 504 s = self._some_str(value)
505 505 if s:
506 506 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
507 507 Colors.Normal, s))
508 508 else:
509 509 list.append('%s\n' % stype)
510 510
511 511 # sync with user hooks
512 512 if have_filedata:
513 513 ipinst = get_ipython()
514 514 if ipinst is not None:
515 515 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
516 516
517 517 return list
518 518
519 519 def get_exception_only(self, etype, value):
520 520 """Only print the exception type and message, without a traceback.
521 521
522 522 Parameters
523 523 ----------
524 524 etype : exception type
525 525 value : exception value
526 526 """
527 527 return ListTB.structured_traceback(self, etype, value)
528 528
529 529 def show_exception_only(self, etype, evalue):
530 530 """Only print the exception type and message, without a traceback.
531 531
532 532 Parameters
533 533 ----------
534 534 etype : exception type
535 535 value : exception value
536 536 """
537 537 # This method needs to use __call__ from *this* class, not the one from
538 538 # a subclass whose signature or behavior may be different
539 539 ostream = self.ostream
540 540 ostream.flush()
541 541 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
542 542 ostream.flush()
543 543
544 544 def _some_str(self, value):
545 545 # Lifted from traceback.py
546 546 try:
547 547 return py3compat.cast_unicode(str(value))
548 548 except:
549 549 return u'<unprintable %s object>' % type(value).__name__
550 550
551 551
552 552 #----------------------------------------------------------------------------
553 553 class VerboseTB(TBTools):
554 554 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
555 555 of HTML. Requires inspect and pydoc. Crazy, man.
556 556
557 557 Modified version which optionally strips the topmost entries from the
558 558 traceback, to be used with alternate interpreters (because their own code
559 559 would appear in the traceback)."""
560 560
561 561 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
562 562 tb_offset=0, long_header=False, include_vars=True,
563 563 check_cache=None, debugger_cls = None,
564 564 parent=None, config=None):
565 565 """Specify traceback offset, headers and color scheme.
566 566
567 567 Define how many frames to drop from the tracebacks. Calling it with
568 568 tb_offset=1 allows use of this handler in interpreters which will have
569 569 their own code at the top of the traceback (VerboseTB will first
570 570 remove that frame before printing the traceback info)."""
571 571 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
572 572 ostream=ostream, parent=parent, config=config)
573 573 self.tb_offset = tb_offset
574 574 self.long_header = long_header
575 575 self.include_vars = include_vars
576 576 # By default we use linecache.checkcache, but the user can provide a
577 577 # different check_cache implementation. This is used by the IPython
578 578 # kernel to provide tracebacks for interactive code that is cached,
579 579 # by a compiler instance that flushes the linecache but preserves its
580 580 # own code cache.
581 581 if check_cache is None:
582 582 check_cache = linecache.checkcache
583 583 self.check_cache = check_cache
584 584
585 585 self.debugger_cls = debugger_cls or debugger.Pdb
586 586
587 587 def format_record(self, frame_info):
588 588 """Format a single stack frame"""
589 589 Colors = self.Colors # just a shorthand + quicker name lookup
590 590 ColorsNormal = Colors.Normal # used a lot
591
592 if isinstance(frame_info, stack_data.RepeatedFrames):
593 return ' %s[... skipping similar frames: %s]%s\n' % (
594 Colors.excName, frame_info.description, ColorsNormal)
595
591 596 col_scheme = self.color_scheme_table.active_scheme_name
592 597 indent = ' ' * INDENT_SIZE
593 598 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
594 599 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
595 600 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
596 601 ColorsNormal)
597 602 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
598 603 (Colors.vName, Colors.valEm, ColorsNormal)
599 604 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
600 605 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
601 606
602 607 file = frame_info.filename
603 608 file = py3compat.cast_unicode(file, util_path.fs_encoding)
604 609 link = tpl_link % util_path.compress_user(file)
605 610 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
606 611
607 612 func = frame_info.executing.code_qualname()
608 613 if func == '<module>':
609 614 call = tpl_call % (func, '')
610 615 else:
611 616 # Decide whether to include variable details or not
612 617 var_repr = eqrepr if self.include_vars else nullrepr
613 618 try:
614 619 call = tpl_call % (func, inspect.formatargvalues(args,
615 620 varargs, varkw,
616 621 locals_, formatvalue=var_repr))
617 622 except KeyError:
618 623 # This happens in situations like errors inside generator
619 624 # expressions, where local variables are listed in the
620 625 # line, but can't be extracted from the frame. I'm not
621 626 # 100% sure this isn't actually a bug in inspect itself,
622 627 # but since there's no info for us to compute with, the
623 628 # best we can do is report the failure and move on. Here
624 629 # we must *not* call any traceback construction again,
625 630 # because that would mess up use of %debug later on. So we
626 631 # simply report the failure and move on. The only
627 632 # limitation will be that this frame won't have locals
628 633 # listed in the call signature. Quite subtle problem...
629 634 # I can't think of a good way to validate this in a unit
630 635 # test, but running a script consisting of:
631 636 # dict( (k,v.strip()) for (k,v) in range(10) )
632 637 # will illustrate the error, if this exception catch is
633 638 # disabled.
634 639 call = tpl_call_fail % func
635 640
636 641 lvals = ''
637 642 lvals_list = []
638 643 if self.include_vars:
639 644 for var in frame_info.variables_in_executing_piece:
640 645 lvals_list.append(tpl_name_val % (var.name, var.value))
641 646 if lvals_list:
642 647 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
643 648
644 649 result = '%s %s\n' % (link, call)
645 650
646 651 _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2
647 652 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, lvals, _line_format))
648 653 return result
649 654
650 655 def prepare_header(self, etype, long_version=False):
651 656 colors = self.Colors # just a shorthand + quicker name lookup
652 657 colorsnormal = colors.Normal # used a lot
653 658 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
654 659 width = min(75, get_terminal_size()[0])
655 660 if long_version:
656 661 # Header with the exception type, python version, and date
657 662 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
658 663 date = time.ctime(time.time())
659 664
660 665 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
661 666 exc, ' ' * (width - len(str(etype)) - len(pyver)),
662 667 pyver, date.rjust(width) )
663 668 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
664 669 "\ncalls leading up to the error, with the most recent (innermost) call last."
665 670 else:
666 671 # Simplified header
667 672 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
668 673 rjust(width - len(str(etype))) )
669 674
670 675 return head
671 676
672 677 def format_exception(self, etype, evalue):
673 678 colors = self.Colors # just a shorthand + quicker name lookup
674 679 colorsnormal = colors.Normal # used a lot
675 680 # Get (safely) a string form of the exception info
676 681 try:
677 682 etype_str, evalue_str = map(str, (etype, evalue))
678 683 except:
679 684 # User exception is improperly defined.
680 685 etype, evalue = str, sys.exc_info()[:2]
681 686 etype_str, evalue_str = map(str, (etype, evalue))
682 687 # ... and format it
683 688 return ['%s%s%s: %s' % (colors.excName, etype_str,
684 689 colorsnormal, py3compat.cast_unicode(evalue_str))]
685 690
686 691 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
687 692 """Formats the header, traceback and exception message for a single exception.
688 693
689 694 This may be called multiple times by Python 3 exception chaining
690 695 (PEP 3134).
691 696 """
692 697 # some locals
693 698 orig_etype = etype
694 699 try:
695 700 etype = etype.__name__
696 701 except AttributeError:
697 702 pass
698 703
699 704 tb_offset = self.tb_offset if tb_offset is None else tb_offset
700 705 head = self.prepare_header(etype, self.long_header)
701 706 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
702 707
703 708 frames = list(map(self.format_record, records))
704 709
705 710 formatted_exception = self.format_exception(etype, evalue)
706 711 if records:
707 712 frame_info = records[-1]
708 713 ipinst = get_ipython()
709 714 if ipinst is not None:
710 715 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
711 716
712 717 return [[head] + frames + [''.join(formatted_exception[0])]]
713 718
714 719 def get_records(self, etb, number_of_lines_of_context, tb_offset):
715 720 context = number_of_lines_of_context - 1
716 721 after = context // 2
717 722 before = context - after
718 723 options = stack_data.Options(before=before, after=after)
719 724 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
720 725
721 726 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
722 727 number_of_lines_of_context=5):
723 728 """Return a nice text document describing the traceback."""
724 729
725 730 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
726 731 tb_offset)
727 732
728 733 colors = self.Colors # just a shorthand + quicker name lookup
729 734 colorsnormal = colors.Normal # used a lot
730 735 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
731 736 structured_traceback_parts = [head]
732 737 chained_exceptions_tb_offset = 0
733 738 lines_of_context = 3
734 739 formatted_exceptions = formatted_exception
735 740 exception = self.get_parts_of_chained_exception(evalue)
736 741 if exception:
737 742 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
738 743 etype, evalue, etb = exception
739 744 else:
740 745 evalue = None
741 746 chained_exc_ids = set()
742 747 while evalue:
743 748 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
744 749 chained_exceptions_tb_offset)
745 750 exception = self.get_parts_of_chained_exception(evalue)
746 751
747 752 if exception and not id(exception[1]) in chained_exc_ids:
748 753 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
749 754 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
750 755 etype, evalue, etb = exception
751 756 else:
752 757 evalue = None
753 758
754 759 # we want to see exceptions in a reversed order:
755 760 # the first exception should be on top
756 761 for formatted_exception in reversed(formatted_exceptions):
757 762 structured_traceback_parts += formatted_exception
758 763
759 764 return structured_traceback_parts
760 765
761 766 def debugger(self, force=False):
762 767 """Call up the pdb debugger if desired, always clean up the tb
763 768 reference.
764 769
765 770 Keywords:
766 771
767 772 - force(False): by default, this routine checks the instance call_pdb
768 773 flag and does not actually invoke the debugger if the flag is false.
769 774 The 'force' option forces the debugger to activate even if the flag
770 775 is false.
771 776
772 777 If the call_pdb flag is set, the pdb interactive debugger is
773 778 invoked. In all cases, the self.tb reference to the current traceback
774 779 is deleted to prevent lingering references which hamper memory
775 780 management.
776 781
777 782 Note that each call to pdb() does an 'import readline', so if your app
778 783 requires a special setup for the readline completers, you'll have to
779 784 fix that by hand after invoking the exception handler."""
780 785
781 786 if force or self.call_pdb:
782 787 if self.pdb is None:
783 788 self.pdb = self.debugger_cls()
784 789 # the system displayhook may have changed, restore the original
785 790 # for pdb
786 791 display_trap = DisplayTrap(hook=sys.__displayhook__)
787 792 with display_trap:
788 793 self.pdb.reset()
789 794 # Find the right frame so we don't pop up inside ipython itself
790 795 if hasattr(self, 'tb') and self.tb is not None:
791 796 etb = self.tb
792 797 else:
793 798 etb = self.tb = sys.last_traceback
794 799 while self.tb is not None and self.tb.tb_next is not None:
795 800 self.tb = self.tb.tb_next
796 801 if etb and etb.tb_next:
797 802 etb = etb.tb_next
798 803 self.pdb.botframe = etb.tb_frame
799 804 self.pdb.interaction(None, etb)
800 805
801 806 if hasattr(self, 'tb'):
802 807 del self.tb
803 808
804 809 def handler(self, info=None):
805 810 (etype, evalue, etb) = info or sys.exc_info()
806 811 self.tb = etb
807 812 ostream = self.ostream
808 813 ostream.flush()
809 814 ostream.write(self.text(etype, evalue, etb))
810 815 ostream.write('\n')
811 816 ostream.flush()
812 817
813 818 # Changed so an instance can just be called as VerboseTB_inst() and print
814 819 # out the right info on its own.
815 820 def __call__(self, etype=None, evalue=None, etb=None):
816 821 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
817 822 if etb is None:
818 823 self.handler()
819 824 else:
820 825 self.handler((etype, evalue, etb))
821 826 try:
822 827 self.debugger()
823 828 except KeyboardInterrupt:
824 829 print("\nKeyboardInterrupt")
825 830
826 831
827 832 #----------------------------------------------------------------------------
828 833 class FormattedTB(VerboseTB, ListTB):
829 834 """Subclass ListTB but allow calling with a traceback.
830 835
831 836 It can thus be used as a sys.excepthook for Python > 2.1.
832 837
833 838 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
834 839
835 840 Allows a tb_offset to be specified. This is useful for situations where
836 841 one needs to remove a number of topmost frames from the traceback (such as
837 842 occurs with python programs that themselves execute other python code,
838 843 like Python shells). """
839 844
840 845 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
841 846 ostream=None,
842 847 tb_offset=0, long_header=False, include_vars=False,
843 848 check_cache=None, debugger_cls=None,
844 849 parent=None, config=None):
845 850
846 851 # NEVER change the order of this list. Put new modes at the end:
847 852 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
848 853 self.verbose_modes = self.valid_modes[1:3]
849 854
850 855 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
851 856 ostream=ostream, tb_offset=tb_offset,
852 857 long_header=long_header, include_vars=include_vars,
853 858 check_cache=check_cache, debugger_cls=debugger_cls,
854 859 parent=parent, config=config)
855 860
856 861 # Different types of tracebacks are joined with different separators to
857 862 # form a single string. They are taken from this dict
858 863 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
859 864 Minimal='')
860 865 # set_mode also sets the tb_join_char attribute
861 866 self.set_mode(mode)
862 867
863 868 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
864 869 tb_offset = self.tb_offset if tb_offset is None else tb_offset
865 870 mode = self.mode
866 871 if mode in self.verbose_modes:
867 872 # Verbose modes need a full traceback
868 873 return VerboseTB.structured_traceback(
869 874 self, etype, value, tb, tb_offset, number_of_lines_of_context
870 875 )
871 876 elif mode == 'Minimal':
872 877 return ListTB.get_exception_only(self, etype, value)
873 878 else:
874 879 # We must check the source cache because otherwise we can print
875 880 # out-of-date source code.
876 881 self.check_cache()
877 882 # Now we can extract and format the exception
878 883 return ListTB.structured_traceback(
879 884 self, etype, value, tb, tb_offset, number_of_lines_of_context
880 885 )
881 886
882 887 def stb2text(self, stb):
883 888 """Convert a structured traceback (a list) to a string."""
884 889 return self.tb_join_char.join(stb)
885 890
886 891
887 892 def set_mode(self, mode=None):
888 893 """Switch to the desired mode.
889 894
890 895 If mode is not specified, cycles through the available modes."""
891 896
892 897 if not mode:
893 898 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
894 899 len(self.valid_modes)
895 900 self.mode = self.valid_modes[new_idx]
896 901 elif mode not in self.valid_modes:
897 902 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
898 903 'Valid modes: ' + str(self.valid_modes))
899 904 else:
900 905 self.mode = mode
901 906 # include variable details only in 'Verbose' mode
902 907 self.include_vars = (self.mode == self.valid_modes[2])
903 908 # Set the join character for generating text tracebacks
904 909 self.tb_join_char = self._join_chars[self.mode]
905 910
906 911 # some convenient shortcuts
907 912 def plain(self):
908 913 self.set_mode(self.valid_modes[0])
909 914
910 915 def context(self):
911 916 self.set_mode(self.valid_modes[1])
912 917
913 918 def verbose(self):
914 919 self.set_mode(self.valid_modes[2])
915 920
916 921 def minimal(self):
917 922 self.set_mode(self.valid_modes[3])
918 923
919 924
920 925 #----------------------------------------------------------------------------
921 926 class AutoFormattedTB(FormattedTB):
922 927 """A traceback printer which can be called on the fly.
923 928
924 929 It will find out about exceptions by itself.
925 930
926 931 A brief example::
927 932
928 933 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
929 934 try:
930 935 ...
931 936 except:
932 937 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
933 938 """
934 939
935 940 def __call__(self, etype=None, evalue=None, etb=None,
936 941 out=None, tb_offset=None):
937 942 """Print out a formatted exception traceback.
938 943
939 944 Optional arguments:
940 945 - out: an open file-like object to direct output to.
941 946
942 947 - tb_offset: the number of frames to skip over in the stack, on a
943 948 per-call basis (this overrides temporarily the instance's tb_offset
944 949 given at initialization time. """
945 950
946 951 if out is None:
947 952 out = self.ostream
948 953 out.flush()
949 954 out.write(self.text(etype, evalue, etb, tb_offset))
950 955 out.write('\n')
951 956 out.flush()
952 957 # FIXME: we should remove the auto pdb behavior from here and leave
953 958 # that to the clients.
954 959 try:
955 960 self.debugger()
956 961 except KeyboardInterrupt:
957 962 print("\nKeyboardInterrupt")
958 963
959 964 def structured_traceback(self, etype=None, value=None, tb=None,
960 965 tb_offset=None, number_of_lines_of_context=5):
961 966 if etype is None:
962 967 etype, value, tb = sys.exc_info()
963 968 if isinstance(tb, tuple):
964 969 # tb is a tuple if this is a chained exception.
965 970 self.tb = tb[0]
966 971 else:
967 972 self.tb = tb
968 973 return FormattedTB.structured_traceback(
969 974 self, etype, value, tb, tb_offset, number_of_lines_of_context)
970 975
971 976
972 977 #---------------------------------------------------------------------------
973 978
974 979 # A simple class to preserve Nathan's original functionality.
975 980 class ColorTB(FormattedTB):
976 981 """Shorthand to initialize a FormattedTB in Linux colors mode."""
977 982
978 983 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
979 984 FormattedTB.__init__(self, color_scheme=color_scheme,
980 985 call_pdb=call_pdb, **kwargs)
981 986
982 987
983 988 class SyntaxTB(ListTB):
984 989 """Extension which holds some state: the last exception value"""
985 990
986 991 def __init__(self, color_scheme='NoColor', parent=None, config=None):
987 992 ListTB.__init__(self, color_scheme, parent=parent, config=config)
988 993 self.last_syntax_error = None
989 994
990 995 def __call__(self, etype, value, elist):
991 996 self.last_syntax_error = value
992 997
993 998 ListTB.__call__(self, etype, value, elist)
994 999
995 1000 def structured_traceback(self, etype, value, elist, tb_offset=None,
996 1001 context=5):
997 1002 # If the source file has been edited, the line in the syntax error can
998 1003 # be wrong (retrieved from an outdated cache). This replaces it with
999 1004 # the current value.
1000 1005 if isinstance(value, SyntaxError) \
1001 1006 and isinstance(value.filename, str) \
1002 1007 and isinstance(value.lineno, int):
1003 1008 linecache.checkcache(value.filename)
1004 1009 newtext = linecache.getline(value.filename, value.lineno)
1005 1010 if newtext:
1006 1011 value.text = newtext
1007 1012 self.last_syntax_error = value
1008 1013 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1009 1014 tb_offset=tb_offset, context=context)
1010 1015
1011 1016 def clear_err_state(self):
1012 1017 """Return the current error state and clear it"""
1013 1018 e = self.last_syntax_error
1014 1019 self.last_syntax_error = None
1015 1020 return e
1016 1021
1017 1022 def stb2text(self, stb):
1018 1023 """Convert a structured traceback (a list) to a string."""
1019 1024 return ''.join(stb)
1020 1025
1021 1026
1022 1027 # some internal-use functions
1023 1028 def text_repr(value):
1024 1029 """Hopefully pretty robust repr equivalent."""
1025 1030 # this is pretty horrible but should always return *something*
1026 1031 try:
1027 1032 return pydoc.text.repr(value)
1028 1033 except KeyboardInterrupt:
1029 1034 raise
1030 1035 except:
1031 1036 try:
1032 1037 return repr(value)
1033 1038 except KeyboardInterrupt:
1034 1039 raise
1035 1040 except:
1036 1041 try:
1037 1042 # all still in an except block so we catch
1038 1043 # getattr raising
1039 1044 name = getattr(value, '__name__', None)
1040 1045 if name:
1041 1046 # ick, recursion
1042 1047 return text_repr(name)
1043 1048 klass = getattr(value, '__class__', None)
1044 1049 if klass:
1045 1050 return '%s instance' % text_repr(klass)
1046 1051 except KeyboardInterrupt:
1047 1052 raise
1048 1053 except:
1049 1054 return 'UNRECOVERABLE REPR FAILURE'
1050 1055
1051 1056
1052 1057 def eqrepr(value, repr=text_repr):
1053 1058 return '=%s' % repr(value)
1054 1059
1055 1060
1056 1061 def nullrepr(value, repr=text_repr):
1057 1062 return ''
General Comments 0
You need to be logged in to leave comments. Login now