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