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