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