##// END OF EJS Templates
Catch SyntaxError from tokenizing for traceback...
Thomas Kluyver -
Show More
@@ -1,1358 +1,1360 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
42 42 Installation instructions for VerboseTB::
43 43
44 44 import sys,ultratb
45 45 sys.excepthook = ultratb.VerboseTB()
46 46
47 47 Note: Much of the code in this module was lifted verbatim from the standard
48 48 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
49 49
50 50 Color schemes
51 51 -------------
52 52
53 53 The colors are defined in the class TBTools through the use of the
54 54 ColorSchemeTable class. Currently the following exist:
55 55
56 56 - NoColor: allows all of this module to be used in any terminal (the color
57 57 escapes are just dummy blank strings).
58 58
59 59 - Linux: is meant to look good in a terminal like the Linux console (black
60 60 or very dark background).
61 61
62 62 - LightBG: similar to Linux but swaps dark/light colors to be more readable
63 63 in light background terminals.
64 64
65 65 You can implement other color schemes easily, the syntax is fairly
66 66 self-explanatory. Please send back new schemes you develop to the author for
67 67 possible inclusion in future releases.
68 68
69 69 Inheritance diagram:
70 70
71 71 .. inheritance-diagram:: IPython.core.ultratb
72 72 :parts: 3
73 73 """
74 74
75 75 #*****************************************************************************
76 76 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
77 77 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
78 78 #
79 79 # Distributed under the terms of the BSD License. The full license is in
80 80 # the file COPYING, distributed as part of this software.
81 81 #*****************************************************************************
82 82
83 83 from __future__ import unicode_literals
84 84 from __future__ import print_function
85 85
86 86 import inspect
87 87 import keyword
88 88 import linecache
89 89 import os
90 90 import pydoc
91 91 import re
92 92 import sys
93 93 import time
94 94 import tokenize
95 95 import traceback
96 96 import types
97 97
98 98 try: # Python 2
99 99 generate_tokens = tokenize.generate_tokens
100 100 except AttributeError: # Python 3
101 101 generate_tokens = tokenize.tokenize
102 102
103 103 # For purposes of monkeypatching inspect to fix a bug in it.
104 104 from inspect import getsourcefile, getfile, getmodule, \
105 105 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
106 106
107 107 # IPython's own modules
108 108 # Modified pdb which doesn't damage IPython's readline handling
109 109 from IPython import get_ipython
110 110 from IPython.core import debugger
111 111 from IPython.core.display_trap import DisplayTrap
112 112 from IPython.core.excolors import exception_colors
113 113 from IPython.utils import PyColorize
114 114 from IPython.utils import io
115 115 from IPython.utils import openpy
116 116 from IPython.utils import path as util_path
117 117 from IPython.utils import py3compat
118 118 from IPython.utils import ulinecache
119 119 from IPython.utils.data import uniq_stable
120 120 from IPython.utils.warn import info, error
121 121
122 122 # Globals
123 123 # amount of space to put line numbers before verbose tracebacks
124 124 INDENT_SIZE = 8
125 125
126 126 # Default color scheme. This is used, for example, by the traceback
127 127 # formatter. When running in an actual IPython instance, the user's rc.colors
128 128 # value is used, but having a module global makes this functionality available
129 129 # to users of ultratb who are NOT running inside ipython.
130 130 DEFAULT_SCHEME = 'NoColor'
131 131
132 132 # ---------------------------------------------------------------------------
133 133 # Code begins
134 134
135 135 # Utility functions
136 136 def inspect_error():
137 137 """Print a message about internal inspect errors.
138 138
139 139 These are unfortunately quite common."""
140 140
141 141 error('Internal Python error in the inspect module.\n'
142 142 'Below is the traceback from this internal error.\n')
143 143
144 144
145 145 # This function is a monkeypatch we apply to the Python inspect module. We have
146 146 # now found when it's needed (see discussion on issue gh-1456), and we have a
147 147 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
148 148 # the monkeypatch is not applied. TK, Aug 2012.
149 149 def findsource(object):
150 150 """Return the entire source file and starting line number for an object.
151 151
152 152 The argument may be a module, class, method, function, traceback, frame,
153 153 or code object. The source code is returned as a list of all the lines
154 154 in the file and the line number indexes a line in that list. An IOError
155 155 is raised if the source code cannot be retrieved.
156 156
157 157 FIXED version with which we monkeypatch the stdlib to work around a bug."""
158 158
159 159 file = getsourcefile(object) or getfile(object)
160 160 # If the object is a frame, then trying to get the globals dict from its
161 161 # module won't work. Instead, the frame object itself has the globals
162 162 # dictionary.
163 163 globals_dict = None
164 164 if inspect.isframe(object):
165 165 # XXX: can this ever be false?
166 166 globals_dict = object.f_globals
167 167 else:
168 168 module = getmodule(object, file)
169 169 if module:
170 170 globals_dict = module.__dict__
171 171 lines = linecache.getlines(file, globals_dict)
172 172 if not lines:
173 173 raise IOError('could not get source code')
174 174
175 175 if ismodule(object):
176 176 return lines, 0
177 177
178 178 if isclass(object):
179 179 name = object.__name__
180 180 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
181 181 # make some effort to find the best matching class definition:
182 182 # use the one with the least indentation, which is the one
183 183 # that's most probably not inside a function definition.
184 184 candidates = []
185 185 for i in range(len(lines)):
186 186 match = pat.match(lines[i])
187 187 if match:
188 188 # if it's at toplevel, it's already the best one
189 189 if lines[i][0] == 'c':
190 190 return lines, i
191 191 # else add whitespace to candidate list
192 192 candidates.append((match.group(1), i))
193 193 if candidates:
194 194 # this will sort by whitespace, and by line number,
195 195 # less whitespace first
196 196 candidates.sort()
197 197 return lines, candidates[0][1]
198 198 else:
199 199 raise IOError('could not find class definition')
200 200
201 201 if ismethod(object):
202 202 object = object.__func__
203 203 if isfunction(object):
204 204 object = object.__code__
205 205 if istraceback(object):
206 206 object = object.tb_frame
207 207 if isframe(object):
208 208 object = object.f_code
209 209 if iscode(object):
210 210 if not hasattr(object, 'co_firstlineno'):
211 211 raise IOError('could not find function definition')
212 212 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
213 213 pmatch = pat.match
214 214 # fperez - fix: sometimes, co_firstlineno can give a number larger than
215 215 # the length of lines, which causes an error. Safeguard against that.
216 216 lnum = min(object.co_firstlineno, len(lines)) - 1
217 217 while lnum > 0:
218 218 if pmatch(lines[lnum]): break
219 219 lnum -= 1
220 220
221 221 return lines, lnum
222 222 raise IOError('could not find code object')
223 223
224 224
225 225 # Monkeypatch inspect to apply our bugfix.
226 226 def with_patch_inspect(f):
227 227 """decorator for monkeypatching inspect.findsource"""
228 228
229 229 def wrapped(*args, **kwargs):
230 230 save_findsource = inspect.findsource
231 231 inspect.findsource = findsource
232 232 try:
233 233 return f(*args, **kwargs)
234 234 finally:
235 235 inspect.findsource = save_findsource
236 236
237 237 return wrapped
238 238
239 239
240 240 def fix_frame_records_filenames(records):
241 241 """Try to fix the filenames in each record from inspect.getinnerframes().
242 242
243 243 Particularly, modules loaded from within zip files have useless filenames
244 244 attached to their code object, and inspect.getinnerframes() just uses it.
245 245 """
246 246 fixed_records = []
247 247 for frame, filename, line_no, func_name, lines, index in records:
248 248 # Look inside the frame's globals dictionary for __file__, which should
249 249 # be better.
250 250 better_fn = frame.f_globals.get('__file__', None)
251 251 if isinstance(better_fn, str):
252 252 # Check the type just in case someone did something weird with
253 253 # __file__. It might also be None if the error occurred during
254 254 # import.
255 255 filename = better_fn
256 256 fixed_records.append((frame, filename, line_no, func_name, lines, index))
257 257 return fixed_records
258 258
259 259
260 260 @with_patch_inspect
261 261 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
262 262 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
263 263
264 264 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
265 265 # If the error is at the console, don't build any context, since it would
266 266 # otherwise produce 5 blank lines printed out (there is no file at the
267 267 # console)
268 268 rec_check = records[tb_offset:]
269 269 try:
270 270 rname = rec_check[0][1]
271 271 if rname == '<ipython console>' or rname.endswith('<string>'):
272 272 return rec_check
273 273 except IndexError:
274 274 pass
275 275
276 276 aux = traceback.extract_tb(etb)
277 277 assert len(records) == len(aux)
278 278 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
279 279 maybeStart = lnum - 1 - context // 2
280 280 start = max(maybeStart, 0)
281 281 end = start + context
282 282 lines = ulinecache.getlines(file)[start:end]
283 283 buf = list(records[i])
284 284 buf[LNUM_POS] = lnum
285 285 buf[INDEX_POS] = lnum - 1 - start
286 286 buf[LINES_POS] = lines
287 287 records[i] = tuple(buf)
288 288 return records[tb_offset:]
289 289
290 290 # Helper function -- largely belongs to VerboseTB, but we need the same
291 291 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
292 292 # can be recognized properly by ipython.el's py-traceback-line-re
293 293 # (SyntaxErrors have to be treated specially because they have no traceback)
294 294
295 295 _parser = PyColorize.Parser()
296 296
297 297
298 298 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
299 299 numbers_width = INDENT_SIZE - 1
300 300 res = []
301 301 i = lnum - index
302 302
303 303 # This lets us get fully syntax-highlighted tracebacks.
304 304 if scheme is None:
305 305 ipinst = get_ipython()
306 306 if ipinst is not None:
307 307 scheme = ipinst.colors
308 308 else:
309 309 scheme = DEFAULT_SCHEME
310 310
311 311 _line_format = _parser.format2
312 312
313 313 for line in lines:
314 314 line = py3compat.cast_unicode(line)
315 315
316 316 new_line, err = _line_format(line, 'str', scheme)
317 317 if not err: line = new_line
318 318
319 319 if i == lnum:
320 320 # This is the line with the error
321 321 pad = numbers_width - len(str(i))
322 322 if pad >= 3:
323 323 marker = '-' * (pad - 3) + '-> '
324 324 elif pad == 2:
325 325 marker = '> '
326 326 elif pad == 1:
327 327 marker = '>'
328 328 else:
329 329 marker = ''
330 330 num = marker + str(i)
331 331 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
332 332 Colors.line, line, Colors.Normal)
333 333 else:
334 334 num = '%*s' % (numbers_width, i)
335 335 line = '%s%s%s %s' % (Colors.lineno, num,
336 336 Colors.Normal, line)
337 337
338 338 res.append(line)
339 339 if lvals and i == lnum:
340 340 res.append(lvals + '\n')
341 341 i = i + 1
342 342 return res
343 343
344 344
345 345 #---------------------------------------------------------------------------
346 346 # Module classes
347 347 class TBTools(object):
348 348 """Basic tools used by all traceback printer classes."""
349 349
350 350 # Number of frames to skip when reporting tracebacks
351 351 tb_offset = 0
352 352
353 353 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
354 354 # Whether to call the interactive pdb debugger after printing
355 355 # tracebacks or not
356 356 self.call_pdb = call_pdb
357 357
358 358 # Output stream to write to. Note that we store the original value in
359 359 # a private attribute and then make the public ostream a property, so
360 360 # that we can delay accessing io.stdout until runtime. The way
361 361 # things are written now, the io.stdout object is dynamically managed
362 362 # so a reference to it should NEVER be stored statically. This
363 363 # property approach confines this detail to a single location, and all
364 364 # subclasses can simply access self.ostream for writing.
365 365 self._ostream = ostream
366 366
367 367 # Create color table
368 368 self.color_scheme_table = exception_colors()
369 369
370 370 self.set_colors(color_scheme)
371 371 self.old_scheme = color_scheme # save initial value for toggles
372 372
373 373 if call_pdb:
374 374 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
375 375 else:
376 376 self.pdb = None
377 377
378 378 def _get_ostream(self):
379 379 """Output stream that exceptions are written to.
380 380
381 381 Valid values are:
382 382
383 383 - None: the default, which means that IPython will dynamically resolve
384 384 to io.stdout. This ensures compatibility with most tools, including
385 385 Windows (where plain stdout doesn't recognize ANSI escapes).
386 386
387 387 - Any object with 'write' and 'flush' attributes.
388 388 """
389 389 return io.stdout if self._ostream is None else self._ostream
390 390
391 391 def _set_ostream(self, val):
392 392 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
393 393 self._ostream = val
394 394
395 395 ostream = property(_get_ostream, _set_ostream)
396 396
397 397 def set_colors(self, *args, **kw):
398 398 """Shorthand access to the color table scheme selector method."""
399 399
400 400 # Set own color table
401 401 self.color_scheme_table.set_active_scheme(*args, **kw)
402 402 # for convenience, set Colors to the active scheme
403 403 self.Colors = self.color_scheme_table.active_colors
404 404 # Also set colors of debugger
405 405 if hasattr(self, 'pdb') and self.pdb is not None:
406 406 self.pdb.set_colors(*args, **kw)
407 407
408 408 def color_toggle(self):
409 409 """Toggle between the currently active color scheme and NoColor."""
410 410
411 411 if self.color_scheme_table.active_scheme_name == 'NoColor':
412 412 self.color_scheme_table.set_active_scheme(self.old_scheme)
413 413 self.Colors = self.color_scheme_table.active_colors
414 414 else:
415 415 self.old_scheme = self.color_scheme_table.active_scheme_name
416 416 self.color_scheme_table.set_active_scheme('NoColor')
417 417 self.Colors = self.color_scheme_table.active_colors
418 418
419 419 def stb2text(self, stb):
420 420 """Convert a structured traceback (a list) to a string."""
421 421 return '\n'.join(stb)
422 422
423 423 def text(self, etype, value, tb, tb_offset=None, context=5):
424 424 """Return formatted traceback.
425 425
426 426 Subclasses may override this if they add extra arguments.
427 427 """
428 428 tb_list = self.structured_traceback(etype, value, tb,
429 429 tb_offset, context)
430 430 return self.stb2text(tb_list)
431 431
432 432 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
433 433 context=5, mode=None):
434 434 """Return a list of traceback frames.
435 435
436 436 Must be implemented by each class.
437 437 """
438 438 raise NotImplementedError()
439 439
440 440
441 441 #---------------------------------------------------------------------------
442 442 class ListTB(TBTools):
443 443 """Print traceback information from a traceback list, with optional color.
444 444
445 445 Calling requires 3 arguments: (etype, evalue, elist)
446 446 as would be obtained by::
447 447
448 448 etype, evalue, tb = sys.exc_info()
449 449 if tb:
450 450 elist = traceback.extract_tb(tb)
451 451 else:
452 452 elist = None
453 453
454 454 It can thus be used by programs which need to process the traceback before
455 455 printing (such as console replacements based on the code module from the
456 456 standard library).
457 457
458 458 Because they are meant to be called without a full traceback (only a
459 459 list), instances of this class can't call the interactive pdb debugger."""
460 460
461 461 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
462 462 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
463 463 ostream=ostream)
464 464
465 465 def __call__(self, etype, value, elist):
466 466 self.ostream.flush()
467 467 self.ostream.write(self.text(etype, value, elist))
468 468 self.ostream.write('\n')
469 469
470 470 def structured_traceback(self, etype, value, elist, tb_offset=None,
471 471 context=5):
472 472 """Return a color formatted string with the traceback info.
473 473
474 474 Parameters
475 475 ----------
476 476 etype : exception type
477 477 Type of the exception raised.
478 478
479 479 value : object
480 480 Data stored in the exception
481 481
482 482 elist : list
483 483 List of frames, see class docstring for details.
484 484
485 485 tb_offset : int, optional
486 486 Number of frames in the traceback to skip. If not given, the
487 487 instance value is used (set in constructor).
488 488
489 489 context : int, optional
490 490 Number of lines of context information to print.
491 491
492 492 Returns
493 493 -------
494 494 String with formatted exception.
495 495 """
496 496 tb_offset = self.tb_offset if tb_offset is None else tb_offset
497 497 Colors = self.Colors
498 498 out_list = []
499 499 if elist:
500 500
501 501 if tb_offset and len(elist) > tb_offset:
502 502 elist = elist[tb_offset:]
503 503
504 504 out_list.append('Traceback %s(most recent call last)%s:' %
505 505 (Colors.normalEm, Colors.Normal) + '\n')
506 506 out_list.extend(self._format_list(elist))
507 507 # The exception info should be a single entry in the list.
508 508 lines = ''.join(self._format_exception_only(etype, value))
509 509 out_list.append(lines)
510 510
511 511 # Note: this code originally read:
512 512
513 513 ## for line in lines[:-1]:
514 514 ## out_list.append(" "+line)
515 515 ## out_list.append(lines[-1])
516 516
517 517 # This means it was indenting everything but the last line by a little
518 518 # bit. I've disabled this for now, but if we see ugliness somewhere we
519 519 # can restore it.
520 520
521 521 return out_list
522 522
523 523 def _format_list(self, extracted_list):
524 524 """Format a list of traceback entry tuples for printing.
525 525
526 526 Given a list of tuples as returned by extract_tb() or
527 527 extract_stack(), return a list of strings ready for printing.
528 528 Each string in the resulting list corresponds to the item with the
529 529 same index in the argument list. Each string ends in a newline;
530 530 the strings may contain internal newlines as well, for those items
531 531 whose source text line is not None.
532 532
533 533 Lifted almost verbatim from traceback.py
534 534 """
535 535
536 536 Colors = self.Colors
537 537 list = []
538 538 for filename, lineno, name, line in extracted_list[:-1]:
539 539 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
540 540 (Colors.filename, filename, Colors.Normal,
541 541 Colors.lineno, lineno, Colors.Normal,
542 542 Colors.name, name, Colors.Normal)
543 543 if line:
544 544 item += ' %s\n' % line.strip()
545 545 list.append(item)
546 546 # Emphasize the last entry
547 547 filename, lineno, name, line = extracted_list[-1]
548 548 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
549 549 (Colors.normalEm,
550 550 Colors.filenameEm, filename, Colors.normalEm,
551 551 Colors.linenoEm, lineno, Colors.normalEm,
552 552 Colors.nameEm, name, Colors.normalEm,
553 553 Colors.Normal)
554 554 if line:
555 555 item += '%s %s%s\n' % (Colors.line, line.strip(),
556 556 Colors.Normal)
557 557 list.append(item)
558 558 return list
559 559
560 560 def _format_exception_only(self, etype, value):
561 561 """Format the exception part of a traceback.
562 562
563 563 The arguments are the exception type and value such as given by
564 564 sys.exc_info()[:2]. The return value is a list of strings, each ending
565 565 in a newline. Normally, the list contains a single string; however,
566 566 for SyntaxError exceptions, it contains several lines that (when
567 567 printed) display detailed information about where the syntax error
568 568 occurred. The message indicating which exception occurred is the
569 569 always last string in the list.
570 570
571 571 Also lifted nearly verbatim from traceback.py
572 572 """
573 573 have_filedata = False
574 574 Colors = self.Colors
575 575 list = []
576 576 stype = Colors.excName + etype.__name__ + Colors.Normal
577 577 if value is None:
578 578 # Not sure if this can still happen in Python 2.6 and above
579 579 list.append(py3compat.cast_unicode(stype) + '\n')
580 580 else:
581 581 if issubclass(etype, SyntaxError):
582 582 have_filedata = True
583 583 if not value.filename: value.filename = "<string>"
584 584 if value.lineno:
585 585 lineno = value.lineno
586 586 textline = ulinecache.getline(value.filename, value.lineno)
587 587 else:
588 588 lineno = 'unknown'
589 589 textline = ''
590 590 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
591 591 (Colors.normalEm,
592 592 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
593 593 Colors.linenoEm, lineno, Colors.Normal ))
594 594 if textline == '':
595 595 textline = py3compat.cast_unicode(value.text, "utf-8")
596 596
597 597 if textline is not None:
598 598 i = 0
599 599 while i < len(textline) and textline[i].isspace():
600 600 i += 1
601 601 list.append('%s %s%s\n' % (Colors.line,
602 602 textline.strip(),
603 603 Colors.Normal))
604 604 if value.offset is not None:
605 605 s = ' '
606 606 for c in textline[i:value.offset - 1]:
607 607 if c.isspace():
608 608 s += c
609 609 else:
610 610 s += ' '
611 611 list.append('%s%s^%s\n' % (Colors.caret, s,
612 612 Colors.Normal))
613 613
614 614 try:
615 615 s = value.msg
616 616 except Exception:
617 617 s = self._some_str(value)
618 618 if s:
619 619 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
620 620 Colors.Normal, s))
621 621 else:
622 622 list.append('%s\n' % str(stype))
623 623
624 624 # sync with user hooks
625 625 if have_filedata:
626 626 ipinst = get_ipython()
627 627 if ipinst is not None:
628 628 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
629 629
630 630 return list
631 631
632 632 def get_exception_only(self, etype, value):
633 633 """Only print the exception type and message, without a traceback.
634 634
635 635 Parameters
636 636 ----------
637 637 etype : exception type
638 638 value : exception value
639 639 """
640 640 return ListTB.structured_traceback(self, etype, value, [])
641 641
642 642 def show_exception_only(self, etype, evalue):
643 643 """Only print the exception type and message, without a traceback.
644 644
645 645 Parameters
646 646 ----------
647 647 etype : exception type
648 648 value : exception value
649 649 """
650 650 # This method needs to use __call__ from *this* class, not the one from
651 651 # a subclass whose signature or behavior may be different
652 652 ostream = self.ostream
653 653 ostream.flush()
654 654 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
655 655 ostream.flush()
656 656
657 657 def _some_str(self, value):
658 658 # Lifted from traceback.py
659 659 try:
660 660 return str(value)
661 661 except:
662 662 return '<unprintable %s object>' % type(value).__name__
663 663
664 664
665 665 #----------------------------------------------------------------------------
666 666 class VerboseTB(TBTools):
667 667 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
668 668 of HTML. Requires inspect and pydoc. Crazy, man.
669 669
670 670 Modified version which optionally strips the topmost entries from the
671 671 traceback, to be used with alternate interpreters (because their own code
672 672 would appear in the traceback)."""
673 673
674 674 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
675 675 tb_offset=0, long_header=False, include_vars=True,
676 676 check_cache=None):
677 677 """Specify traceback offset, headers and color scheme.
678 678
679 679 Define how many frames to drop from the tracebacks. Calling it with
680 680 tb_offset=1 allows use of this handler in interpreters which will have
681 681 their own code at the top of the traceback (VerboseTB will first
682 682 remove that frame before printing the traceback info)."""
683 683 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
684 684 ostream=ostream)
685 685 self.tb_offset = tb_offset
686 686 self.long_header = long_header
687 687 self.include_vars = include_vars
688 688 # By default we use linecache.checkcache, but the user can provide a
689 689 # different check_cache implementation. This is used by the IPython
690 690 # kernel to provide tracebacks for interactive code that is cached,
691 691 # by a compiler instance that flushes the linecache but preserves its
692 692 # own code cache.
693 693 if check_cache is None:
694 694 check_cache = linecache.checkcache
695 695 self.check_cache = check_cache
696 696
697 697 def format_records(self, records):
698 698 Colors = self.Colors # just a shorthand + quicker name lookup
699 699 ColorsNormal = Colors.Normal # used a lot
700 700 col_scheme = self.color_scheme_table.active_scheme_name
701 701 indent = ' ' * INDENT_SIZE
702 702 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
703 703 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
704 704 frames = []
705 705 # build some color string templates outside these nested loops
706 706 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
707 707 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
708 708 ColorsNormal)
709 709 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
710 710 (Colors.vName, Colors.valEm, ColorsNormal)
711 711 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
712 712 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
713 713 Colors.vName, ColorsNormal)
714 714 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
715 715
716 716 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
717 717 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
718 718 ColorsNormal)
719 719
720 720 abspath = os.path.abspath
721 721 for frame, file, lnum, func, lines, index in records:
722 722 #print '*** record:',file,lnum,func,lines,index # dbg
723 723 if not file:
724 724 file = '?'
725 725 elif not (file.startswith(str("<")) and file.endswith(str(">"))):
726 726 # Guess that filenames like <string> aren't real filenames, so
727 727 # don't call abspath on them.
728 728 try:
729 729 file = abspath(file)
730 730 except OSError:
731 731 # Not sure if this can still happen: abspath now works with
732 732 # file names like <string>
733 733 pass
734 734 file = py3compat.cast_unicode(file, util_path.fs_encoding)
735 735 link = tpl_link % file
736 736 args, varargs, varkw, locals = inspect.getargvalues(frame)
737 737
738 738 if func == '?':
739 739 call = ''
740 740 else:
741 741 # Decide whether to include variable details or not
742 742 var_repr = self.include_vars and eqrepr or nullrepr
743 743 try:
744 744 call = tpl_call % (func, inspect.formatargvalues(args,
745 745 varargs, varkw,
746 746 locals, formatvalue=var_repr))
747 747 except KeyError:
748 748 # This happens in situations like errors inside generator
749 749 # expressions, where local variables are listed in the
750 750 # line, but can't be extracted from the frame. I'm not
751 751 # 100% sure this isn't actually a bug in inspect itself,
752 752 # but since there's no info for us to compute with, the
753 753 # best we can do is report the failure and move on. Here
754 754 # we must *not* call any traceback construction again,
755 755 # because that would mess up use of %debug later on. So we
756 756 # simply report the failure and move on. The only
757 757 # limitation will be that this frame won't have locals
758 758 # listed in the call signature. Quite subtle problem...
759 759 # I can't think of a good way to validate this in a unit
760 760 # test, but running a script consisting of:
761 761 # dict( (k,v.strip()) for (k,v) in range(10) )
762 762 # will illustrate the error, if this exception catch is
763 763 # disabled.
764 764 call = tpl_call_fail % func
765 765
766 766 # Don't attempt to tokenize binary files.
767 767 if file.endswith(('.so', '.pyd', '.dll')):
768 768 frames.append('%s %s\n' % (link, call))
769 769 continue
770 770 elif file.endswith(('.pyc', '.pyo')):
771 771 # Look up the corresponding source file.
772 772 file = openpy.source_from_cache(file)
773 773
774 774 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
775 775 line = getline(file, lnum[0])
776 776 lnum[0] += 1
777 777 return line
778 778
779 779 # Build the list of names on this line of code where the exception
780 780 # occurred.
781 781 try:
782 782 names = []
783 783 name_cont = False
784 784
785 785 for token_type, token, start, end, line in generate_tokens(linereader):
786 786 # build composite names
787 787 if token_type == tokenize.NAME and token not in keyword.kwlist:
788 788 if name_cont:
789 789 # Continuation of a dotted name
790 790 try:
791 791 names[-1].append(token)
792 792 except IndexError:
793 793 names.append([token])
794 794 name_cont = False
795 795 else:
796 796 # Regular new names. We append everything, the caller
797 797 # will be responsible for pruning the list later. It's
798 798 # very tricky to try to prune as we go, b/c composite
799 799 # names can fool us. The pruning at the end is easy
800 800 # to do (or the caller can print a list with repeated
801 801 # names if so desired.
802 802 names.append([token])
803 803 elif token == '.':
804 804 name_cont = True
805 805 elif token_type == tokenize.NEWLINE:
806 806 break
807 807
808 except (IndexError, UnicodeDecodeError):
808 except (IndexError, UnicodeDecodeError, SyntaxError):
809 809 # signals exit of tokenizer
810 # SyntaxError can occur if the file is not actually Python
811 # - see gh-6300
810 812 pass
811 813 except tokenize.TokenError as msg:
812 814 _m = ("An unexpected error occurred while tokenizing input\n"
813 815 "The following traceback may be corrupted or invalid\n"
814 816 "The error message is: %s\n" % msg)
815 817 error(_m)
816 818
817 819 # Join composite names (e.g. "dict.fromkeys")
818 820 names = ['.'.join(n) for n in names]
819 821 # prune names list of duplicates, but keep the right order
820 822 unique_names = uniq_stable(names)
821 823
822 824 # Start loop over vars
823 825 lvals = []
824 826 if self.include_vars:
825 827 for name_full in unique_names:
826 828 name_base = name_full.split('.', 1)[0]
827 829 if name_base in frame.f_code.co_varnames:
828 830 if name_base in locals:
829 831 try:
830 832 value = repr(eval(name_full, locals))
831 833 except:
832 834 value = undefined
833 835 else:
834 836 value = undefined
835 837 name = tpl_local_var % name_full
836 838 else:
837 839 if name_base in frame.f_globals:
838 840 try:
839 841 value = repr(eval(name_full, frame.f_globals))
840 842 except:
841 843 value = undefined
842 844 else:
843 845 value = undefined
844 846 name = tpl_global_var % name_full
845 847 lvals.append(tpl_name_val % (name, value))
846 848 if lvals:
847 849 lvals = '%s%s' % (indent, em_normal.join(lvals))
848 850 else:
849 851 lvals = ''
850 852
851 853 level = '%s %s\n' % (link, call)
852 854
853 855 if index is None:
854 856 frames.append(level)
855 857 else:
856 858 frames.append('%s%s' % (level, ''.join(
857 859 _format_traceback_lines(lnum, index, lines, Colors, lvals,
858 860 col_scheme))))
859 861
860 862 return frames
861 863
862 864 def prepare_chained_exception_message(self, cause):
863 865 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
864 866 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
865 867
866 868 if cause:
867 869 message = [[direct_cause]]
868 870 else:
869 871 message = [[exception_during_handling]]
870 872 return message
871 873
872 874 def prepare_header(self, etype, long_version=False):
873 875 colors = self.Colors # just a shorthand + quicker name lookup
874 876 colorsnormal = colors.Normal # used a lot
875 877 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
876 878 if long_version:
877 879 # Header with the exception type, python version, and date
878 880 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
879 881 date = time.ctime(time.time())
880 882
881 883 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
882 884 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
883 885 pyver, date.rjust(75) )
884 886 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
885 887 "\ncalls leading up to the error, with the most recent (innermost) call last."
886 888 else:
887 889 # Simplified header
888 890 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
889 891 rjust(75 - len(str(etype))) )
890 892
891 893 return head
892 894
893 895 def format_exception(self, etype, evalue):
894 896 colors = self.Colors # just a shorthand + quicker name lookup
895 897 colorsnormal = colors.Normal # used a lot
896 898 indent = ' ' * INDENT_SIZE
897 899 # Get (safely) a string form of the exception info
898 900 try:
899 901 etype_str, evalue_str = map(str, (etype, evalue))
900 902 except:
901 903 # User exception is improperly defined.
902 904 etype, evalue = str, sys.exc_info()[:2]
903 905 etype_str, evalue_str = map(str, (etype, evalue))
904 906 # ... and format it
905 907 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
906 908 colorsnormal, py3compat.cast_unicode(evalue_str))]
907 909
908 910 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
909 911 try:
910 912 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
911 913 except:
912 914 # Every now and then, an object with funny internals blows up
913 915 # when dir() is called on it. We do the best we can to report
914 916 # the problem and continue
915 917 _m = '%sException reporting error (object with broken dir())%s:'
916 918 exception.append(_m % (colors.excName, colorsnormal))
917 919 etype_str, evalue_str = map(str, sys.exc_info()[:2])
918 920 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
919 921 colorsnormal, py3compat.cast_unicode(evalue_str)))
920 922 names = []
921 923 for name in names:
922 924 value = text_repr(getattr(evalue, name))
923 925 exception.append('\n%s%s = %s' % (indent, name, value))
924 926
925 927 return exception
926 928
927 929 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
928 930 # some locals
929 931 try:
930 932 etype = etype.__name__
931 933 except AttributeError:
932 934 pass
933 935
934 936 tb_offset = self.tb_offset if tb_offset is None else tb_offset
935 937 head = self.prepare_header(etype, self.long_header)
936 938 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
937 939
938 940 frames = self.format_records(records)
939 941 if records is None:
940 942 return ""
941 943
942 944 formatted_exception = self.format_exception(etype, evalue)
943 945 if records:
944 946 filepath, lnum = records[-1][1:3]
945 947 filepath = os.path.abspath(filepath)
946 948 ipinst = get_ipython()
947 949 if ipinst is not None:
948 950 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
949 951
950 952 return [[head] + frames + [''.join(formatted_exception[0])]]
951 953
952 954 def get_records(self, etb, number_of_lines_of_context, tb_offset):
953 955 try:
954 956 # Try the default getinnerframes and Alex's: Alex's fixes some
955 957 # problems, but it generates empty tracebacks for console errors
956 958 # (5 blanks lines) where none should be returned.
957 959 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
958 960 except:
959 961 # FIXME: I've been getting many crash reports from python 2.3
960 962 # users, traceable to inspect.py. If I can find a small test-case
961 963 # to reproduce this, I should either write a better workaround or
962 964 # file a bug report against inspect (if that's the real problem).
963 965 # So far, I haven't been able to find an isolated example to
964 966 # reproduce the problem.
965 967 inspect_error()
966 968 traceback.print_exc(file=self.ostream)
967 969 info('\nUnfortunately, your original traceback can not be constructed.\n')
968 970 return None
969 971
970 972 def get_parts_of_chained_exception(self, evalue):
971 973 def get_chained_exception(exception_value):
972 974 cause = getattr(exception_value, '__cause__', None)
973 975 if cause:
974 976 return cause
975 977 return getattr(exception_value, '__context__', None)
976 978
977 979 chained_evalue = get_chained_exception(evalue)
978 980
979 981 if chained_evalue:
980 982 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
981 983
982 984 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
983 985 number_of_lines_of_context=5):
984 986 """Return a nice text document describing the traceback."""
985 987
986 988 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
987 989 tb_offset)
988 990
989 991 colors = self.Colors # just a shorthand + quicker name lookup
990 992 colorsnormal = colors.Normal # used a lot
991 993 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
992 994 structured_traceback_parts = [head]
993 995 if py3compat.PY3:
994 996 chained_exceptions_tb_offset = 0
995 997 lines_of_context = 3
996 998 formatted_exceptions = formatted_exception
997 999 exception = self.get_parts_of_chained_exception(evalue)
998 1000 if exception:
999 1001 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1000 1002 etype, evalue, etb = exception
1001 1003 else:
1002 1004 evalue = None
1003 1005 while evalue:
1004 1006 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1005 1007 chained_exceptions_tb_offset)
1006 1008 exception = self.get_parts_of_chained_exception(evalue)
1007 1009
1008 1010 if exception:
1009 1011 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1010 1012 etype, evalue, etb = exception
1011 1013 else:
1012 1014 evalue = None
1013 1015
1014 1016 # we want to see exceptions in a reversed order:
1015 1017 # the first exception should be on top
1016 1018 for formatted_exception in reversed(formatted_exceptions):
1017 1019 structured_traceback_parts += formatted_exception
1018 1020 else:
1019 1021 structured_traceback_parts += formatted_exception[0]
1020 1022
1021 1023 return structured_traceback_parts
1022 1024
1023 1025 def debugger(self, force=False):
1024 1026 """Call up the pdb debugger if desired, always clean up the tb
1025 1027 reference.
1026 1028
1027 1029 Keywords:
1028 1030
1029 1031 - force(False): by default, this routine checks the instance call_pdb
1030 1032 flag and does not actually invoke the debugger if the flag is false.
1031 1033 The 'force' option forces the debugger to activate even if the flag
1032 1034 is false.
1033 1035
1034 1036 If the call_pdb flag is set, the pdb interactive debugger is
1035 1037 invoked. In all cases, the self.tb reference to the current traceback
1036 1038 is deleted to prevent lingering references which hamper memory
1037 1039 management.
1038 1040
1039 1041 Note that each call to pdb() does an 'import readline', so if your app
1040 1042 requires a special setup for the readline completers, you'll have to
1041 1043 fix that by hand after invoking the exception handler."""
1042 1044
1043 1045 if force or self.call_pdb:
1044 1046 if self.pdb is None:
1045 1047 self.pdb = debugger.Pdb(
1046 1048 self.color_scheme_table.active_scheme_name)
1047 1049 # the system displayhook may have changed, restore the original
1048 1050 # for pdb
1049 1051 display_trap = DisplayTrap(hook=sys.__displayhook__)
1050 1052 with display_trap:
1051 1053 self.pdb.reset()
1052 1054 # Find the right frame so we don't pop up inside ipython itself
1053 1055 if hasattr(self, 'tb') and self.tb is not None:
1054 1056 etb = self.tb
1055 1057 else:
1056 1058 etb = self.tb = sys.last_traceback
1057 1059 while self.tb is not None and self.tb.tb_next is not None:
1058 1060 self.tb = self.tb.tb_next
1059 1061 if etb and etb.tb_next:
1060 1062 etb = etb.tb_next
1061 1063 self.pdb.botframe = etb.tb_frame
1062 1064 self.pdb.interaction(self.tb.tb_frame, self.tb)
1063 1065
1064 1066 if hasattr(self, 'tb'):
1065 1067 del self.tb
1066 1068
1067 1069 def handler(self, info=None):
1068 1070 (etype, evalue, etb) = info or sys.exc_info()
1069 1071 self.tb = etb
1070 1072 ostream = self.ostream
1071 1073 ostream.flush()
1072 1074 ostream.write(self.text(etype, evalue, etb))
1073 1075 ostream.write('\n')
1074 1076 ostream.flush()
1075 1077
1076 1078 # Changed so an instance can just be called as VerboseTB_inst() and print
1077 1079 # out the right info on its own.
1078 1080 def __call__(self, etype=None, evalue=None, etb=None):
1079 1081 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1080 1082 if etb is None:
1081 1083 self.handler()
1082 1084 else:
1083 1085 self.handler((etype, evalue, etb))
1084 1086 try:
1085 1087 self.debugger()
1086 1088 except KeyboardInterrupt:
1087 1089 print("\nKeyboardInterrupt")
1088 1090
1089 1091
1090 1092 #----------------------------------------------------------------------------
1091 1093 class FormattedTB(VerboseTB, ListTB):
1092 1094 """Subclass ListTB but allow calling with a traceback.
1093 1095
1094 1096 It can thus be used as a sys.excepthook for Python > 2.1.
1095 1097
1096 1098 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1097 1099
1098 1100 Allows a tb_offset to be specified. This is useful for situations where
1099 1101 one needs to remove a number of topmost frames from the traceback (such as
1100 1102 occurs with python programs that themselves execute other python code,
1101 1103 like Python shells). """
1102 1104
1103 1105 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1104 1106 ostream=None,
1105 1107 tb_offset=0, long_header=False, include_vars=False,
1106 1108 check_cache=None):
1107 1109
1108 1110 # NEVER change the order of this list. Put new modes at the end:
1109 1111 self.valid_modes = ['Plain', 'Context', 'Verbose']
1110 1112 self.verbose_modes = self.valid_modes[1:3]
1111 1113
1112 1114 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1113 1115 ostream=ostream, tb_offset=tb_offset,
1114 1116 long_header=long_header, include_vars=include_vars,
1115 1117 check_cache=check_cache)
1116 1118
1117 1119 # Different types of tracebacks are joined with different separators to
1118 1120 # form a single string. They are taken from this dict
1119 1121 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1120 1122 # set_mode also sets the tb_join_char attribute
1121 1123 self.set_mode(mode)
1122 1124
1123 1125 def _extract_tb(self, tb):
1124 1126 if tb:
1125 1127 return traceback.extract_tb(tb)
1126 1128 else:
1127 1129 return None
1128 1130
1129 1131 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1130 1132 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1131 1133 mode = self.mode
1132 1134 if mode in self.verbose_modes:
1133 1135 # Verbose modes need a full traceback
1134 1136 return VerboseTB.structured_traceback(
1135 1137 self, etype, value, tb, tb_offset, number_of_lines_of_context
1136 1138 )
1137 1139 else:
1138 1140 # We must check the source cache because otherwise we can print
1139 1141 # out-of-date source code.
1140 1142 self.check_cache()
1141 1143 # Now we can extract and format the exception
1142 1144 elist = self._extract_tb(tb)
1143 1145 return ListTB.structured_traceback(
1144 1146 self, etype, value, elist, tb_offset, number_of_lines_of_context
1145 1147 )
1146 1148
1147 1149 def stb2text(self, stb):
1148 1150 """Convert a structured traceback (a list) to a string."""
1149 1151 return self.tb_join_char.join(stb)
1150 1152
1151 1153
1152 1154 def set_mode(self, mode=None):
1153 1155 """Switch to the desired mode.
1154 1156
1155 1157 If mode is not specified, cycles through the available modes."""
1156 1158
1157 1159 if not mode:
1158 1160 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1159 1161 len(self.valid_modes)
1160 1162 self.mode = self.valid_modes[new_idx]
1161 1163 elif mode not in self.valid_modes:
1162 1164 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1163 1165 'Valid modes: ' + str(self.valid_modes))
1164 1166 else:
1165 1167 self.mode = mode
1166 1168 # include variable details only in 'Verbose' mode
1167 1169 self.include_vars = (self.mode == self.valid_modes[2])
1168 1170 # Set the join character for generating text tracebacks
1169 1171 self.tb_join_char = self._join_chars[self.mode]
1170 1172
1171 1173 # some convenient shortcuts
1172 1174 def plain(self):
1173 1175 self.set_mode(self.valid_modes[0])
1174 1176
1175 1177 def context(self):
1176 1178 self.set_mode(self.valid_modes[1])
1177 1179
1178 1180 def verbose(self):
1179 1181 self.set_mode(self.valid_modes[2])
1180 1182
1181 1183
1182 1184 #----------------------------------------------------------------------------
1183 1185 class AutoFormattedTB(FormattedTB):
1184 1186 """A traceback printer which can be called on the fly.
1185 1187
1186 1188 It will find out about exceptions by itself.
1187 1189
1188 1190 A brief example::
1189 1191
1190 1192 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1191 1193 try:
1192 1194 ...
1193 1195 except:
1194 1196 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1195 1197 """
1196 1198
1197 1199 def __call__(self, etype=None, evalue=None, etb=None,
1198 1200 out=None, tb_offset=None):
1199 1201 """Print out a formatted exception traceback.
1200 1202
1201 1203 Optional arguments:
1202 1204 - out: an open file-like object to direct output to.
1203 1205
1204 1206 - tb_offset: the number of frames to skip over in the stack, on a
1205 1207 per-call basis (this overrides temporarily the instance's tb_offset
1206 1208 given at initialization time. """
1207 1209
1208 1210 if out is None:
1209 1211 out = self.ostream
1210 1212 out.flush()
1211 1213 out.write(self.text(etype, evalue, etb, tb_offset))
1212 1214 out.write('\n')
1213 1215 out.flush()
1214 1216 # FIXME: we should remove the auto pdb behavior from here and leave
1215 1217 # that to the clients.
1216 1218 try:
1217 1219 self.debugger()
1218 1220 except KeyboardInterrupt:
1219 1221 print("\nKeyboardInterrupt")
1220 1222
1221 1223 def structured_traceback(self, etype=None, value=None, tb=None,
1222 1224 tb_offset=None, number_of_lines_of_context=5):
1223 1225 if etype is None:
1224 1226 etype, value, tb = sys.exc_info()
1225 1227 self.tb = tb
1226 1228 return FormattedTB.structured_traceback(
1227 1229 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1228 1230
1229 1231
1230 1232 #---------------------------------------------------------------------------
1231 1233
1232 1234 # A simple class to preserve Nathan's original functionality.
1233 1235 class ColorTB(FormattedTB):
1234 1236 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1235 1237
1236 1238 def __init__(self, color_scheme='Linux', call_pdb=0):
1237 1239 FormattedTB.__init__(self, color_scheme=color_scheme,
1238 1240 call_pdb=call_pdb)
1239 1241
1240 1242
1241 1243 class SyntaxTB(ListTB):
1242 1244 """Extension which holds some state: the last exception value"""
1243 1245
1244 1246 def __init__(self, color_scheme='NoColor'):
1245 1247 ListTB.__init__(self, color_scheme)
1246 1248 self.last_syntax_error = None
1247 1249
1248 1250 def __call__(self, etype, value, elist):
1249 1251 self.last_syntax_error = value
1250 1252
1251 1253 ListTB.__call__(self, etype, value, elist)
1252 1254
1253 1255 def structured_traceback(self, etype, value, elist, tb_offset=None,
1254 1256 context=5):
1255 1257 # If the source file has been edited, the line in the syntax error can
1256 1258 # be wrong (retrieved from an outdated cache). This replaces it with
1257 1259 # the current value.
1258 1260 if isinstance(value, SyntaxError) \
1259 1261 and isinstance(value.filename, py3compat.string_types) \
1260 1262 and isinstance(value.lineno, int):
1261 1263 linecache.checkcache(value.filename)
1262 1264 newtext = ulinecache.getline(value.filename, value.lineno)
1263 1265 if newtext:
1264 1266 value.text = newtext
1265 1267 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1266 1268 tb_offset=tb_offset, context=context)
1267 1269
1268 1270 def clear_err_state(self):
1269 1271 """Return the current error state and clear it"""
1270 1272 e = self.last_syntax_error
1271 1273 self.last_syntax_error = None
1272 1274 return e
1273 1275
1274 1276 def stb2text(self, stb):
1275 1277 """Convert a structured traceback (a list) to a string."""
1276 1278 return ''.join(stb)
1277 1279
1278 1280
1279 1281 # some internal-use functions
1280 1282 def text_repr(value):
1281 1283 """Hopefully pretty robust repr equivalent."""
1282 1284 # this is pretty horrible but should always return *something*
1283 1285 try:
1284 1286 return pydoc.text.repr(value)
1285 1287 except KeyboardInterrupt:
1286 1288 raise
1287 1289 except:
1288 1290 try:
1289 1291 return repr(value)
1290 1292 except KeyboardInterrupt:
1291 1293 raise
1292 1294 except:
1293 1295 try:
1294 1296 # all still in an except block so we catch
1295 1297 # getattr raising
1296 1298 name = getattr(value, '__name__', None)
1297 1299 if name:
1298 1300 # ick, recursion
1299 1301 return text_repr(name)
1300 1302 klass = getattr(value, '__class__', None)
1301 1303 if klass:
1302 1304 return '%s instance' % text_repr(klass)
1303 1305 except KeyboardInterrupt:
1304 1306 raise
1305 1307 except:
1306 1308 return 'UNRECOVERABLE REPR FAILURE'
1307 1309
1308 1310
1309 1311 def eqrepr(value, repr=text_repr):
1310 1312 return '=%s' % repr(value)
1311 1313
1312 1314
1313 1315 def nullrepr(value, repr=text_repr):
1314 1316 return ''
1315 1317
1316 1318
1317 1319 #----------------------------------------------------------------------------
1318 1320
1319 1321 # module testing (minimal)
1320 1322 if __name__ == "__main__":
1321 1323 def spam(c, d_e):
1322 1324 (d, e) = d_e
1323 1325 x = c + d
1324 1326 y = c * d
1325 1327 foo(x, y)
1326 1328
1327 1329 def foo(a, b, bar=1):
1328 1330 eggs(a, b + bar)
1329 1331
1330 1332 def eggs(f, g, z=globals()):
1331 1333 h = f + g
1332 1334 i = f - g
1333 1335 return h / i
1334 1336
1335 1337 print('')
1336 1338 print('*** Before ***')
1337 1339 try:
1338 1340 print(spam(1, (2, 3)))
1339 1341 except:
1340 1342 traceback.print_exc()
1341 1343 print('')
1342 1344
1343 1345 handler = ColorTB()
1344 1346 print('*** ColorTB ***')
1345 1347 try:
1346 1348 print(spam(1, (2, 3)))
1347 1349 except:
1348 1350 handler(*sys.exc_info())
1349 1351 print('')
1350 1352
1351 1353 handler = VerboseTB()
1352 1354 print('*** VerboseTB ***')
1353 1355 try:
1354 1356 print(spam(1, (2, 3)))
1355 1357 except:
1356 1358 handler(*sys.exc_info())
1357 1359 print('')
1358 1360
General Comments 0
You need to be logged in to leave comments. Login now