##// END OF EJS Templates
Fix coloring
martinRenou -
Show More
@@ -1,1122 +1,1122 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 def _format_filename(file, Colors, ColorNormal):
172 def _format_filename(file, ColorFilename, ColorNormal):
173 173 """
174 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module...
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 Colors
180 ColorScheme used.
181 ColorsNormal
179 ColorFilename
180 ColorScheme's filename coloring to be used.
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 tpl_link = "In %s%%s%s" % (Colors.filenameEm, ColorNormal)
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 tpl_link = "File %s%%s%s" % (Colors.filenameEm, ColorNormal)
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 _format_filename(filename, Colors, Colors.normalEm),
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 _format_filename(filename, Colors, Colors.normalEm),
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 _format_filename(value.filename, Colors, Colors.normalEm),
507 _format_filename(value.filename, Colors.filenameEm, Colors.normalEm),
508 508 Colors.linenoEm,
509 509 lineno,
510 510 Colors.Normal,
511 511 )
512 512 )
513 513 if textline == "":
514 514 textline = py3compat.cast_unicode(value.text, "utf-8")
515 515
516 516 if textline is not None:
517 517 i = 0
518 518 while i < len(textline) and textline[i].isspace():
519 519 i += 1
520 520 list.append('%s %s%s\n' % (Colors.line,
521 521 textline.strip(),
522 522 Colors.Normal))
523 523 if value.offset is not None:
524 524 s = ' '
525 525 for c in textline[i:value.offset - 1]:
526 526 if c.isspace():
527 527 s += c
528 528 else:
529 529 s += ' '
530 530 list.append('%s%s^%s\n' % (Colors.caret, s,
531 531 Colors.Normal))
532 532
533 533 try:
534 534 s = value.msg
535 535 except Exception:
536 536 s = self._some_str(value)
537 537 if s:
538 538 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
539 539 Colors.Normal, s))
540 540 else:
541 541 list.append('%s\n' % stype)
542 542
543 543 # sync with user hooks
544 544 if have_filedata:
545 545 ipinst = get_ipython()
546 546 if ipinst is not None:
547 547 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
548 548
549 549 return list
550 550
551 551 def get_exception_only(self, etype, value):
552 552 """Only print the exception type and message, without a traceback.
553 553
554 554 Parameters
555 555 ----------
556 556 etype : exception type
557 557 evalue : exception value
558 558 """
559 559 return ListTB.structured_traceback(self, etype, value)
560 560
561 561 def show_exception_only(self, etype, evalue):
562 562 """Only print the exception type and message, without a traceback.
563 563
564 564 Parameters
565 565 ----------
566 566 etype : exception type
567 567 evalue : exception value
568 568 """
569 569 # This method needs to use __call__ from *this* class, not the one from
570 570 # a subclass whose signature or behavior may be different
571 571 ostream = self.ostream
572 572 ostream.flush()
573 573 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
574 574 ostream.flush()
575 575
576 576 def _some_str(self, value):
577 577 # Lifted from traceback.py
578 578 try:
579 579 return py3compat.cast_unicode(str(value))
580 580 except:
581 581 return u'<unprintable %s object>' % type(value).__name__
582 582
583 583
584 584 #----------------------------------------------------------------------------
585 585 class VerboseTB(TBTools):
586 586 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
587 587 of HTML. Requires inspect and pydoc. Crazy, man.
588 588
589 589 Modified version which optionally strips the topmost entries from the
590 590 traceback, to be used with alternate interpreters (because their own code
591 591 would appear in the traceback)."""
592 592
593 593 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
594 594 tb_offset=0, long_header=False, include_vars=True,
595 595 check_cache=None, debugger_cls = None,
596 596 parent=None, config=None):
597 597 """Specify traceback offset, headers and color scheme.
598 598
599 599 Define how many frames to drop from the tracebacks. Calling it with
600 600 tb_offset=1 allows use of this handler in interpreters which will have
601 601 their own code at the top of the traceback (VerboseTB will first
602 602 remove that frame before printing the traceback info)."""
603 603 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
604 604 ostream=ostream, parent=parent, config=config)
605 605 self.tb_offset = tb_offset
606 606 self.long_header = long_header
607 607 self.include_vars = include_vars
608 608 # By default we use linecache.checkcache, but the user can provide a
609 609 # different check_cache implementation. This is used by the IPython
610 610 # kernel to provide tracebacks for interactive code that is cached,
611 611 # by a compiler instance that flushes the linecache but preserves its
612 612 # own code cache.
613 613 if check_cache is None:
614 614 check_cache = linecache.checkcache
615 615 self.check_cache = check_cache
616 616
617 617 self.debugger_cls = debugger_cls or debugger.Pdb
618 618 self.skip_hidden = True
619 619
620 620 def format_record(self, frame_info):
621 621 """Format a single stack frame"""
622 622 Colors = self.Colors # just a shorthand + quicker name lookup
623 623 ColorsNormal = Colors.Normal # used a lot
624 624
625 625 if isinstance(frame_info, stack_data.RepeatedFrames):
626 626 return ' %s[... skipping similar frames: %s]%s\n' % (
627 627 Colors.excName, frame_info.description, ColorsNormal)
628 628
629 629 indent = ' ' * INDENT_SIZE
630 630 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
631 631 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
632 632 ColorsNormal)
633 633 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
634 634 (Colors.vName, Colors.valEm, ColorsNormal)
635 635 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
636 636
637 link = _format_filename(frame_info.filename, Colors, ColorsNormal)
637 link = _format_filename(frame_info.filename, Colors.filenameEm, ColorsNormal)
638 638 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
639 639
640 640 func = frame_info.executing.code_qualname()
641 641 if func == '<module>':
642 642 call = tpl_call % (func, '')
643 643 else:
644 644 # Decide whether to include variable details or not
645 645 var_repr = eqrepr if self.include_vars else nullrepr
646 646 try:
647 647 call = tpl_call % (func, inspect.formatargvalues(args,
648 648 varargs, varkw,
649 649 locals_, formatvalue=var_repr))
650 650 except KeyError:
651 651 # This happens in situations like errors inside generator
652 652 # expressions, where local variables are listed in the
653 653 # line, but can't be extracted from the frame. I'm not
654 654 # 100% sure this isn't actually a bug in inspect itself,
655 655 # but since there's no info for us to compute with, the
656 656 # best we can do is report the failure and move on. Here
657 657 # we must *not* call any traceback construction again,
658 658 # because that would mess up use of %debug later on. So we
659 659 # simply report the failure and move on. The only
660 660 # limitation will be that this frame won't have locals
661 661 # listed in the call signature. Quite subtle problem...
662 662 # I can't think of a good way to validate this in a unit
663 663 # test, but running a script consisting of:
664 664 # dict( (k,v.strip()) for (k,v) in range(10) )
665 665 # will illustrate the error, if this exception catch is
666 666 # disabled.
667 667 call = tpl_call_fail % func
668 668
669 669 lvals = ''
670 670 lvals_list = []
671 671 if self.include_vars:
672 672 for var in frame_info.variables_in_executing_piece:
673 673 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
674 674 if lvals_list:
675 675 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
676 676
677 677 result = "%s, %s\n" % (link, call)
678 678
679 679 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
680 680 return result
681 681
682 682 def prepare_header(self, etype, long_version=False):
683 683 colors = self.Colors # just a shorthand + quicker name lookup
684 684 colorsnormal = colors.Normal # used a lot
685 685 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
686 686 width = min(75, get_terminal_size()[0])
687 687 if long_version:
688 688 # Header with the exception type, python version, and date
689 689 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
690 690 date = time.ctime(time.time())
691 691
692 692 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
693 693 exc, ' ' * (width - len(str(etype)) - len(pyver)),
694 694 pyver, date.rjust(width) )
695 695 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
696 696 "\ncalls leading up to the error, with the most recent (innermost) call last."
697 697 else:
698 698 # Simplified header
699 699 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
700 700 rjust(width - len(str(etype))) )
701 701
702 702 return head
703 703
704 704 def format_exception(self, etype, evalue):
705 705 colors = self.Colors # just a shorthand + quicker name lookup
706 706 colorsnormal = colors.Normal # used a lot
707 707 # Get (safely) a string form of the exception info
708 708 try:
709 709 etype_str, evalue_str = map(str, (etype, evalue))
710 710 except:
711 711 # User exception is improperly defined.
712 712 etype, evalue = str, sys.exc_info()[:2]
713 713 etype_str, evalue_str = map(str, (etype, evalue))
714 714 # ... and format it
715 715 return ['%s%s%s: %s' % (colors.excName, etype_str,
716 716 colorsnormal, py3compat.cast_unicode(evalue_str))]
717 717
718 718 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
719 719 """Formats the header, traceback and exception message for a single exception.
720 720
721 721 This may be called multiple times by Python 3 exception chaining
722 722 (PEP 3134).
723 723 """
724 724 # some locals
725 725 orig_etype = etype
726 726 try:
727 727 etype = etype.__name__
728 728 except AttributeError:
729 729 pass
730 730
731 731 tb_offset = self.tb_offset if tb_offset is None else tb_offset
732 732 head = self.prepare_header(etype, self.long_header)
733 733 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
734 734
735 735 frames = []
736 736 skipped = 0
737 737 lastrecord = len(records) - 1
738 738 for i, r in enumerate(records):
739 739 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
740 740 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
741 741 skipped += 1
742 742 continue
743 743 if skipped:
744 744 Colors = self.Colors # just a shorthand + quicker name lookup
745 745 ColorsNormal = Colors.Normal # used a lot
746 746 frames.append(
747 747 " %s[... skipping hidden %s frame]%s\n"
748 748 % (Colors.excName, skipped, ColorsNormal)
749 749 )
750 750 skipped = 0
751 751 frames.append(self.format_record(r))
752 752 if skipped:
753 753 Colors = self.Colors # just a shorthand + quicker name lookup
754 754 ColorsNormal = Colors.Normal # used a lot
755 755 frames.append(
756 756 " %s[... skipping hidden %s frame]%s\n"
757 757 % (Colors.excName, skipped, ColorsNormal)
758 758 )
759 759
760 760 formatted_exception = self.format_exception(etype, evalue)
761 761 if records:
762 762 frame_info = records[-1]
763 763 ipinst = get_ipython()
764 764 if ipinst is not None:
765 765 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
766 766
767 767 return [[head] + frames + [''.join(formatted_exception[0])]]
768 768
769 769 def get_records(self, etb, number_of_lines_of_context, tb_offset):
770 770 context = number_of_lines_of_context - 1
771 771 after = context // 2
772 772 before = context - after
773 773 if self.has_colors:
774 774 style = get_style_by_name('default')
775 775 style = stack_data.style_with_executing_node(style, 'bg:#00005f')
776 776 formatter = Terminal256Formatter(style=style)
777 777 else:
778 778 formatter = None
779 779 options = stack_data.Options(
780 780 before=before,
781 781 after=after,
782 782 pygments_formatter=formatter,
783 783 )
784 784 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
785 785
786 786 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
787 787 number_of_lines_of_context=5):
788 788 """Return a nice text document describing the traceback."""
789 789
790 790 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
791 791 tb_offset)
792 792
793 793 colors = self.Colors # just a shorthand + quicker name lookup
794 794 colorsnormal = colors.Normal # used a lot
795 795 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
796 796 structured_traceback_parts = [head]
797 797 chained_exceptions_tb_offset = 0
798 798 lines_of_context = 3
799 799 formatted_exceptions = formatted_exception
800 800 exception = self.get_parts_of_chained_exception(evalue)
801 801 if exception:
802 802 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
803 803 etype, evalue, etb = exception
804 804 else:
805 805 evalue = None
806 806 chained_exc_ids = set()
807 807 while evalue:
808 808 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
809 809 chained_exceptions_tb_offset)
810 810 exception = self.get_parts_of_chained_exception(evalue)
811 811
812 812 if exception and not id(exception[1]) in chained_exc_ids:
813 813 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
814 814 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
815 815 etype, evalue, etb = exception
816 816 else:
817 817 evalue = None
818 818
819 819 # we want to see exceptions in a reversed order:
820 820 # the first exception should be on top
821 821 for formatted_exception in reversed(formatted_exceptions):
822 822 structured_traceback_parts += formatted_exception
823 823
824 824 return structured_traceback_parts
825 825
826 826 def debugger(self, force=False):
827 827 """Call up the pdb debugger if desired, always clean up the tb
828 828 reference.
829 829
830 830 Keywords:
831 831
832 832 - force(False): by default, this routine checks the instance call_pdb
833 833 flag and does not actually invoke the debugger if the flag is false.
834 834 The 'force' option forces the debugger to activate even if the flag
835 835 is false.
836 836
837 837 If the call_pdb flag is set, the pdb interactive debugger is
838 838 invoked. In all cases, the self.tb reference to the current traceback
839 839 is deleted to prevent lingering references which hamper memory
840 840 management.
841 841
842 842 Note that each call to pdb() does an 'import readline', so if your app
843 843 requires a special setup for the readline completers, you'll have to
844 844 fix that by hand after invoking the exception handler."""
845 845
846 846 if force or self.call_pdb:
847 847 if self.pdb is None:
848 848 self.pdb = self.debugger_cls()
849 849 # the system displayhook may have changed, restore the original
850 850 # for pdb
851 851 display_trap = DisplayTrap(hook=sys.__displayhook__)
852 852 with display_trap:
853 853 self.pdb.reset()
854 854 # Find the right frame so we don't pop up inside ipython itself
855 855 if hasattr(self, 'tb') and self.tb is not None:
856 856 etb = self.tb
857 857 else:
858 858 etb = self.tb = sys.last_traceback
859 859 while self.tb is not None and self.tb.tb_next is not None:
860 860 self.tb = self.tb.tb_next
861 861 if etb and etb.tb_next:
862 862 etb = etb.tb_next
863 863 self.pdb.botframe = etb.tb_frame
864 864 self.pdb.interaction(None, etb)
865 865
866 866 if hasattr(self, 'tb'):
867 867 del self.tb
868 868
869 869 def handler(self, info=None):
870 870 (etype, evalue, etb) = info or sys.exc_info()
871 871 self.tb = etb
872 872 ostream = self.ostream
873 873 ostream.flush()
874 874 ostream.write(self.text(etype, evalue, etb))
875 875 ostream.write('\n')
876 876 ostream.flush()
877 877
878 878 # Changed so an instance can just be called as VerboseTB_inst() and print
879 879 # out the right info on its own.
880 880 def __call__(self, etype=None, evalue=None, etb=None):
881 881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
882 882 if etb is None:
883 883 self.handler()
884 884 else:
885 885 self.handler((etype, evalue, etb))
886 886 try:
887 887 self.debugger()
888 888 except KeyboardInterrupt:
889 889 print("\nKeyboardInterrupt")
890 890
891 891
892 892 #----------------------------------------------------------------------------
893 893 class FormattedTB(VerboseTB, ListTB):
894 894 """Subclass ListTB but allow calling with a traceback.
895 895
896 896 It can thus be used as a sys.excepthook for Python > 2.1.
897 897
898 898 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
899 899
900 900 Allows a tb_offset to be specified. This is useful for situations where
901 901 one needs to remove a number of topmost frames from the traceback (such as
902 902 occurs with python programs that themselves execute other python code,
903 903 like Python shells). """
904 904
905 905 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
906 906 ostream=None,
907 907 tb_offset=0, long_header=False, include_vars=False,
908 908 check_cache=None, debugger_cls=None,
909 909 parent=None, config=None):
910 910
911 911 # NEVER change the order of this list. Put new modes at the end:
912 912 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
913 913 self.verbose_modes = self.valid_modes[1:3]
914 914
915 915 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
916 916 ostream=ostream, tb_offset=tb_offset,
917 917 long_header=long_header, include_vars=include_vars,
918 918 check_cache=check_cache, debugger_cls=debugger_cls,
919 919 parent=parent, config=config)
920 920
921 921 # Different types of tracebacks are joined with different separators to
922 922 # form a single string. They are taken from this dict
923 923 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
924 924 Minimal='')
925 925 # set_mode also sets the tb_join_char attribute
926 926 self.set_mode(mode)
927 927
928 928 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
929 929 tb_offset = self.tb_offset if tb_offset is None else tb_offset
930 930 mode = self.mode
931 931 if mode in self.verbose_modes:
932 932 # Verbose modes need a full traceback
933 933 return VerboseTB.structured_traceback(
934 934 self, etype, value, tb, tb_offset, number_of_lines_of_context
935 935 )
936 936 elif mode == 'Minimal':
937 937 return ListTB.get_exception_only(self, etype, value)
938 938 else:
939 939 # We must check the source cache because otherwise we can print
940 940 # out-of-date source code.
941 941 self.check_cache()
942 942 # Now we can extract and format the exception
943 943 return ListTB.structured_traceback(
944 944 self, etype, value, tb, tb_offset, number_of_lines_of_context
945 945 )
946 946
947 947 def stb2text(self, stb):
948 948 """Convert a structured traceback (a list) to a string."""
949 949 return self.tb_join_char.join(stb)
950 950
951 951
952 952 def set_mode(self, mode=None):
953 953 """Switch to the desired mode.
954 954
955 955 If mode is not specified, cycles through the available modes."""
956 956
957 957 if not mode:
958 958 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
959 959 len(self.valid_modes)
960 960 self.mode = self.valid_modes[new_idx]
961 961 elif mode not in self.valid_modes:
962 962 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
963 963 'Valid modes: ' + str(self.valid_modes))
964 964 else:
965 965 self.mode = mode
966 966 # include variable details only in 'Verbose' mode
967 967 self.include_vars = (self.mode == self.valid_modes[2])
968 968 # Set the join character for generating text tracebacks
969 969 self.tb_join_char = self._join_chars[self.mode]
970 970
971 971 # some convenient shortcuts
972 972 def plain(self):
973 973 self.set_mode(self.valid_modes[0])
974 974
975 975 def context(self):
976 976 self.set_mode(self.valid_modes[1])
977 977
978 978 def verbose(self):
979 979 self.set_mode(self.valid_modes[2])
980 980
981 981 def minimal(self):
982 982 self.set_mode(self.valid_modes[3])
983 983
984 984
985 985 #----------------------------------------------------------------------------
986 986 class AutoFormattedTB(FormattedTB):
987 987 """A traceback printer which can be called on the fly.
988 988
989 989 It will find out about exceptions by itself.
990 990
991 991 A brief example::
992 992
993 993 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
994 994 try:
995 995 ...
996 996 except:
997 997 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
998 998 """
999 999
1000 1000 def __call__(self, etype=None, evalue=None, etb=None,
1001 1001 out=None, tb_offset=None):
1002 1002 """Print out a formatted exception traceback.
1003 1003
1004 1004 Optional arguments:
1005 1005 - out: an open file-like object to direct output to.
1006 1006
1007 1007 - tb_offset: the number of frames to skip over in the stack, on a
1008 1008 per-call basis (this overrides temporarily the instance's tb_offset
1009 1009 given at initialization time."""
1010 1010
1011 1011 if out is None:
1012 1012 out = self.ostream
1013 1013 out.flush()
1014 1014 out.write(self.text(etype, evalue, etb, tb_offset))
1015 1015 out.write('\n')
1016 1016 out.flush()
1017 1017 # FIXME: we should remove the auto pdb behavior from here and leave
1018 1018 # that to the clients.
1019 1019 try:
1020 1020 self.debugger()
1021 1021 except KeyboardInterrupt:
1022 1022 print("\nKeyboardInterrupt")
1023 1023
1024 1024 def structured_traceback(self, etype=None, value=None, tb=None,
1025 1025 tb_offset=None, number_of_lines_of_context=5):
1026 1026 if etype is None:
1027 1027 etype, value, tb = sys.exc_info()
1028 1028 if isinstance(tb, tuple):
1029 1029 # tb is a tuple if this is a chained exception.
1030 1030 self.tb = tb[0]
1031 1031 else:
1032 1032 self.tb = tb
1033 1033 return FormattedTB.structured_traceback(
1034 1034 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1035 1035
1036 1036
1037 1037 #---------------------------------------------------------------------------
1038 1038
1039 1039 # A simple class to preserve Nathan's original functionality.
1040 1040 class ColorTB(FormattedTB):
1041 1041 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1042 1042
1043 1043 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1044 1044 FormattedTB.__init__(self, color_scheme=color_scheme,
1045 1045 call_pdb=call_pdb, **kwargs)
1046 1046
1047 1047
1048 1048 class SyntaxTB(ListTB):
1049 1049 """Extension which holds some state: the last exception value"""
1050 1050
1051 1051 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1052 1052 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1053 1053 self.last_syntax_error = None
1054 1054
1055 1055 def __call__(self, etype, value, elist):
1056 1056 self.last_syntax_error = value
1057 1057
1058 1058 ListTB.__call__(self, etype, value, elist)
1059 1059
1060 1060 def structured_traceback(self, etype, value, elist, tb_offset=None,
1061 1061 context=5):
1062 1062 # If the source file has been edited, the line in the syntax error can
1063 1063 # be wrong (retrieved from an outdated cache). This replaces it with
1064 1064 # the current value.
1065 1065 if isinstance(value, SyntaxError) \
1066 1066 and isinstance(value.filename, str) \
1067 1067 and isinstance(value.lineno, int):
1068 1068 linecache.checkcache(value.filename)
1069 1069 newtext = linecache.getline(value.filename, value.lineno)
1070 1070 if newtext:
1071 1071 value.text = newtext
1072 1072 self.last_syntax_error = value
1073 1073 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1074 1074 tb_offset=tb_offset, context=context)
1075 1075
1076 1076 def clear_err_state(self):
1077 1077 """Return the current error state and clear it"""
1078 1078 e = self.last_syntax_error
1079 1079 self.last_syntax_error = None
1080 1080 return e
1081 1081
1082 1082 def stb2text(self, stb):
1083 1083 """Convert a structured traceback (a list) to a string."""
1084 1084 return ''.join(stb)
1085 1085
1086 1086
1087 1087 # some internal-use functions
1088 1088 def text_repr(value):
1089 1089 """Hopefully pretty robust repr equivalent."""
1090 1090 # this is pretty horrible but should always return *something*
1091 1091 try:
1092 1092 return pydoc.text.repr(value)
1093 1093 except KeyboardInterrupt:
1094 1094 raise
1095 1095 except:
1096 1096 try:
1097 1097 return repr(value)
1098 1098 except KeyboardInterrupt:
1099 1099 raise
1100 1100 except:
1101 1101 try:
1102 1102 # all still in an except block so we catch
1103 1103 # getattr raising
1104 1104 name = getattr(value, '__name__', None)
1105 1105 if name:
1106 1106 # ick, recursion
1107 1107 return text_repr(name)
1108 1108 klass = getattr(value, '__class__', None)
1109 1109 if klass:
1110 1110 return '%s instance' % text_repr(klass)
1111 1111 except KeyboardInterrupt:
1112 1112 raise
1113 1113 except:
1114 1114 return 'UNRECOVERABLE REPR FAILURE'
1115 1115
1116 1116
1117 1117 def eqrepr(value, repr=text_repr):
1118 1118 return '=%s' % repr(value)
1119 1119
1120 1120
1121 1121 def nullrepr(value, repr=text_repr):
1122 1122 return ''
General Comments 0
You need to be logged in to leave comments. Login now