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