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