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