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