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