##// END OF EJS Templates
i1673 implementation of py3 proper error handling...
Justyna Ilczuk -
Show More

The requested changes are too big and content was truncated. Show full diff

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