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