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