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