##// END OF EJS Templates
Fix exception color problems in win32....
Fernando Perez -
Show More
@@ -1,121 +1,121 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Release data for the IPython project."""
3 3
4 4 #*****************************************************************************
5 5 # Copyright (C) 2008-2009 The IPython Development Team
6 6 # Copyright (C) 2001-2008 Fernando Perez <fperez@colorado.edu>
7 7 # Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
8 8 # <n8gray@caltech.edu>
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #*****************************************************************************
13 13
14 14 # Name of the package for release purposes. This is the name which labels
15 15 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
16 16 name = 'ipython'
17 17
18 18 # For versions with substrings (like 0.6.16.svn), use an extra . to separate
19 19 # the new substring. We have to avoid using either dashes or underscores,
20 20 # because bdist_rpm does not accept dashes (an RPM) convention, and
21 21 # bdist_deb does not accept underscores (a Debian convention).
22 22
23 23 development = True # change this to False to do a release
24 24 version_base = '0.11'
25 25 branch = 'ipython'
26 revision = '1284'
26 revision = '1312'
27 27
28 28 if development:
29 29 if branch == 'ipython':
30 30 version = '%s.bzr.r%s' % (version_base, revision)
31 31 else:
32 32 version = '%s.bzr.r%s.%s' % (version_base, revision, branch)
33 33 else:
34 34 version = version_base
35 35
36 36
37 37 description = "An interactive computing environment for Python"
38 38
39 39 long_description = \
40 40 """
41 41 The goal of IPython is to create a comprehensive environment for
42 42 interactive and exploratory computing. To support this goal, IPython
43 43 has two main components:
44 44
45 45 * An enhanced interactive Python shell.
46 46
47 47 * An architecture for interactive parallel computing.
48 48
49 49 The enhanced interactive Python shell has the following main features:
50 50
51 51 * Comprehensive object introspection.
52 52
53 53 * Input history, persistent across sessions.
54 54
55 55 * Caching of output results during a session with automatically generated
56 56 references.
57 57
58 58 * Readline based name completion.
59 59
60 60 * Extensible system of 'magic' commands for controlling the environment and
61 61 performing many tasks related either to IPython or the operating system.
62 62
63 63 * Configuration system with easy switching between different setups (simpler
64 64 than changing $PYTHONSTARTUP environment variables every time).
65 65
66 66 * Session logging and reloading.
67 67
68 68 * Extensible syntax processing for special purpose situations.
69 69
70 70 * Access to the system shell with user-extensible alias system.
71 71
72 72 * Easily embeddable in other Python programs and wxPython GUIs.
73 73
74 74 * Integrated access to the pdb debugger and the Python profiler.
75 75
76 76 The parallel computing architecture has the following main features:
77 77
78 78 * Quickly parallelize Python code from an interactive Python/IPython session.
79 79
80 80 * A flexible and dynamic process model that be deployed on anything from
81 81 multicore workstations to supercomputers.
82 82
83 83 * An architecture that supports many different styles of parallelism, from
84 84 message passing to task farming.
85 85
86 86 * Both blocking and fully asynchronous interfaces.
87 87
88 88 * High level APIs that enable many things to be parallelized in a few lines
89 89 of code.
90 90
91 91 * Share live parallel jobs with other users securely.
92 92
93 93 * Dynamically load balanced task farming system.
94 94
95 95 * Robust error handling in parallel code.
96 96
97 97 The latest development version is always available from IPython's `Launchpad
98 98 site <http://launchpad.net/ipython>`_.
99 99 """
100 100
101 101 license = 'BSD'
102 102
103 103 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
104 104 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
105 105 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
106 106 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
107 107 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
108 108 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com')
109 109 }
110 110
111 111 author = 'The IPython Development Team'
112 112
113 113 author_email = 'ipython-dev@scipy.org'
114 114
115 115 url = 'http://ipython.scipy.org'
116 116
117 117 download_url = 'http://ipython.scipy.org/dist'
118 118
119 119 platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
120 120
121 121 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed']
@@ -1,1098 +1,1101 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 with_statement
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 string
81 81 import sys
82 82 import time
83 83 import tokenize
84 84 import traceback
85 85 import types
86 86
87 87 # For purposes of monkeypatching inspect to fix a bug in it.
88 88 from inspect import getsourcefile, getfile, getmodule,\
89 89 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
90 90
91
92 91 # IPython's own modules
93 92 # Modified pdb which doesn't damage IPython's readline handling
94 93 from IPython.utils import PyColorize
95 94 from IPython.core import debugger, ipapi
96 95 from IPython.core.display_trap import DisplayTrap
97 96 from IPython.utils.ipstruct import Struct
98 97 from IPython.core.excolors import exception_colors
99 98 from IPython.utils.genutils import Term, uniq_stable, error, info
100 99
101 100 # Globals
102 101 # amount of space to put line numbers before verbose tracebacks
103 102 INDENT_SIZE = 8
104 103
105 104 # Default color scheme. This is used, for example, by the traceback
106 105 # formatter. When running in an actual IPython instance, the user's rc.colors
107 106 # value is used, but havinga module global makes this functionality available
108 107 # to users of ultratb who are NOT running inside ipython.
109 108 DEFAULT_SCHEME = 'NoColor'
110 109
111 110 #---------------------------------------------------------------------------
112 111 # Code begins
113 112
114 113 # Utility functions
115 114 def inspect_error():
116 115 """Print a message about internal inspect errors.
117 116
118 117 These are unfortunately quite common."""
119 118
120 119 error('Internal Python error in the inspect module.\n'
121 120 'Below is the traceback from this internal error.\n')
122 121
123 122
124 123 def findsource(object):
125 124 """Return the entire source file and starting line number for an object.
126 125
127 126 The argument may be a module, class, method, function, traceback, frame,
128 127 or code object. The source code is returned as a list of all the lines
129 128 in the file and the line number indexes a line in that list. An IOError
130 129 is raised if the source code cannot be retrieved.
131 130
132 131 FIXED version with which we monkeypatch the stdlib to work around a bug."""
133 132
134 133 file = getsourcefile(object) or getfile(object)
135 134 # If the object is a frame, then trying to get the globals dict from its
136 135 # module won't work. Instead, the frame object itself has the globals
137 136 # dictionary.
138 137 globals_dict = None
139 138 if inspect.isframe(object):
140 139 # XXX: can this ever be false?
141 140 globals_dict = object.f_globals
142 141 else:
143 142 module = getmodule(object, file)
144 143 if module:
145 144 globals_dict = module.__dict__
146 145 lines = linecache.getlines(file, globals_dict)
147 146 if not lines:
148 147 raise IOError('could not get source code')
149 148
150 149 if ismodule(object):
151 150 return lines, 0
152 151
153 152 if isclass(object):
154 153 name = object.__name__
155 154 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
156 155 # make some effort to find the best matching class definition:
157 156 # use the one with the least indentation, which is the one
158 157 # that's most probably not inside a function definition.
159 158 candidates = []
160 159 for i in range(len(lines)):
161 160 match = pat.match(lines[i])
162 161 if match:
163 162 # if it's at toplevel, it's already the best one
164 163 if lines[i][0] == 'c':
165 164 return lines, i
166 165 # else add whitespace to candidate list
167 166 candidates.append((match.group(1), i))
168 167 if candidates:
169 168 # this will sort by whitespace, and by line number,
170 169 # less whitespace first
171 170 candidates.sort()
172 171 return lines, candidates[0][1]
173 172 else:
174 173 raise IOError('could not find class definition')
175 174
176 175 if ismethod(object):
177 176 object = object.im_func
178 177 if isfunction(object):
179 178 object = object.func_code
180 179 if istraceback(object):
181 180 object = object.tb_frame
182 181 if isframe(object):
183 182 object = object.f_code
184 183 if iscode(object):
185 184 if not hasattr(object, 'co_firstlineno'):
186 185 raise IOError('could not find function definition')
187 186 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
188 187 pmatch = pat.match
189 188 # fperez - fix: sometimes, co_firstlineno can give a number larger than
190 189 # the length of lines, which causes an error. Safeguard against that.
191 190 lnum = min(object.co_firstlineno,len(lines))-1
192 191 while lnum > 0:
193 192 if pmatch(lines[lnum]): break
194 193 lnum -= 1
195 194
196 195 return lines, lnum
197 196 raise IOError('could not find code object')
198 197
199 198 # Monkeypatch inspect to apply our bugfix. This code only works with py25
200 199 if sys.version_info[:2] >= (2,5):
201 200 inspect.findsource = findsource
202 201
203 202 def fix_frame_records_filenames(records):
204 203 """Try to fix the filenames in each record from inspect.getinnerframes().
205 204
206 205 Particularly, modules loaded from within zip files have useless filenames
207 206 attached to their code object, and inspect.getinnerframes() just uses it.
208 207 """
209 208 fixed_records = []
210 209 for frame, filename, line_no, func_name, lines, index in records:
211 210 # Look inside the frame's globals dictionary for __file__, which should
212 211 # be better.
213 212 better_fn = frame.f_globals.get('__file__', None)
214 213 if isinstance(better_fn, str):
215 214 # Check the type just in case someone did something weird with
216 215 # __file__. It might also be None if the error occurred during
217 216 # import.
218 217 filename = better_fn
219 218 fixed_records.append((frame, filename, line_no, func_name, lines, index))
220 219 return fixed_records
221 220
222 221
223 222 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
224 223 import linecache
225 224 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
226 225
227 226 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
228 227
229 228 # If the error is at the console, don't build any context, since it would
230 229 # otherwise produce 5 blank lines printed out (there is no file at the
231 230 # console)
232 231 rec_check = records[tb_offset:]
233 232 try:
234 233 rname = rec_check[0][1]
235 234 if rname == '<ipython console>' or rname.endswith('<string>'):
236 235 return rec_check
237 236 except IndexError:
238 237 pass
239 238
240 239 aux = traceback.extract_tb(etb)
241 240 assert len(records) == len(aux)
242 241 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
243 242 maybeStart = lnum-1 - context//2
244 243 start = max(maybeStart, 0)
245 244 end = start + context
246 245 lines = linecache.getlines(file)[start:end]
247 246 # pad with empty lines if necessary
248 247 if maybeStart < 0:
249 248 lines = (['\n'] * -maybeStart) + lines
250 249 if len(lines) < context:
251 250 lines += ['\n'] * (context - len(lines))
252 251 buf = list(records[i])
253 252 buf[LNUM_POS] = lnum
254 253 buf[INDEX_POS] = lnum - 1 - start
255 254 buf[LINES_POS] = lines
256 255 records[i] = tuple(buf)
257 256 return records[tb_offset:]
258 257
259 258 # Helper function -- largely belongs to VerboseTB, but we need the same
260 259 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
261 260 # can be recognized properly by ipython.el's py-traceback-line-re
262 261 # (SyntaxErrors have to be treated specially because they have no traceback)
263 262
264 263 _parser = PyColorize.Parser()
265 264
266 265 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
267 266 numbers_width = INDENT_SIZE - 1
268 267 res = []
269 268 i = lnum - index
270 269
271 270 # This lets us get fully syntax-highlighted tracebacks.
272 271 if scheme is None:
273 272 ipinst = ipapi.get()
274 273 if ipinst is not None:
275 274 scheme = ipinst.colors
276 275 else:
277 276 scheme = DEFAULT_SCHEME
278 277
279 278 _line_format = _parser.format2
280 279
281 280 for line in lines:
282 281 new_line, err = _line_format(line,'str',scheme)
283 282 if not err: line = new_line
284 283
285 284 if i == lnum:
286 285 # This is the line with the error
287 286 pad = numbers_width - len(str(i))
288 287 if pad >= 3:
289 288 marker = '-'*(pad-3) + '-> '
290 289 elif pad == 2:
291 290 marker = '> '
292 291 elif pad == 1:
293 292 marker = '>'
294 293 else:
295 294 marker = ''
296 295 num = marker + str(i)
297 296 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 297 Colors.line, line, Colors.Normal)
299 298 else:
300 299 num = '%*s' % (numbers_width,i)
301 300 line = '%s%s%s %s' %(Colors.lineno, num,
302 301 Colors.Normal, line)
303 302
304 303 res.append(line)
305 304 if lvals and i == lnum:
306 305 res.append(lvals + '\n')
307 306 i = i + 1
308 307 return res
309 308
310 309
311 310 #---------------------------------------------------------------------------
312 311 # Module classes
313 312 class TBTools:
314 313 """Basic tools used by all traceback printer classes."""
314
315 315 #: Default output stream, can be overridden at call time. A special value
316 316 #: of 'stdout' *as a string* can be given to force extraction of sys.stdout
317 317 #: at runtime. This allows testing exception printing with doctests, that
318 318 #: swap sys.stdout just at execution time.
319 out_stream = sys.stderr
319 #: Warning: be VERY careful to set this to one of the Term streams, NEVER
320 #: directly to sys.stdout/err, because under win32 the Term streams come from
321 #: pyreadline and know how to handle color correctly, whie stdout/err don't.
322 out_stream = Term.cerr
320 323
321 324 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
322 325 # Whether to call the interactive pdb debugger after printing
323 326 # tracebacks or not
324 327 self.call_pdb = call_pdb
325 328
326 329 # Create color table
327 330 self.color_scheme_table = exception_colors()
328 331
329 332 self.set_colors(color_scheme)
330 333 self.old_scheme = color_scheme # save initial value for toggles
331 334
332 335 if call_pdb:
333 336 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
334 337 else:
335 338 self.pdb = None
336 339
337 340 def set_colors(self,*args,**kw):
338 341 """Shorthand access to the color table scheme selector method."""
339 342
340 343 # Set own color table
341 344 self.color_scheme_table.set_active_scheme(*args,**kw)
342 345 # for convenience, set Colors to the active scheme
343 346 self.Colors = self.color_scheme_table.active_colors
344 347 # Also set colors of debugger
345 348 if hasattr(self,'pdb') and self.pdb is not None:
346 349 self.pdb.set_colors(*args,**kw)
347 350
348 351 def color_toggle(self):
349 352 """Toggle between the currently active color scheme and NoColor."""
350 353
351 354 if self.color_scheme_table.active_scheme_name == 'NoColor':
352 355 self.color_scheme_table.set_active_scheme(self.old_scheme)
353 356 self.Colors = self.color_scheme_table.active_colors
354 357 else:
355 358 self.old_scheme = self.color_scheme_table.active_scheme_name
356 359 self.color_scheme_table.set_active_scheme('NoColor')
357 360 self.Colors = self.color_scheme_table.active_colors
358 361
359 362 #---------------------------------------------------------------------------
360 363 class ListTB(TBTools):
361 364 """Print traceback information from a traceback list, with optional color.
362 365
363 366 Calling: requires 3 arguments:
364 367 (etype, evalue, elist)
365 368 as would be obtained by:
366 369 etype, evalue, tb = sys.exc_info()
367 370 if tb:
368 371 elist = traceback.extract_tb(tb)
369 372 else:
370 373 elist = None
371 374
372 375 It can thus be used by programs which need to process the traceback before
373 376 printing (such as console replacements based on the code module from the
374 377 standard library).
375 378
376 379 Because they are meant to be called without a full traceback (only a
377 380 list), instances of this class can't call the interactive pdb debugger."""
378 381
379 382 def __init__(self,color_scheme = 'NoColor'):
380 383 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
381 384
382 385 def __call__(self, etype, value, elist):
383 386 Term.cout.flush()
384 print >> Term.cerr, self.text(etype,value,elist)
385 Term.cerr.flush()
387 Term.cerr.writeln(self.text(etype,value,elist))
386 388
387 389 def text(self, etype, value, elist, context=5):
388 390 """Return a color formatted string with the traceback info.
389 391
390 392 Parameters
391 393 ----------
392 394 etype : exception type
393 395 Type of the exception raised.
394 396
395 397 value : object
396 398 Data stored in the exception
397 399
398 400 elist : list
399 401 List of frames, see class docstring for details.
400 402
401 403 Returns
402 404 -------
403 405 String with formatted exception.
404 406 """
405 407
406 408 Colors = self.Colors
407 409 out_string = []
408 410 if elist:
409 411 out_string.append('Traceback %s(most recent call last)%s:' %
410 412 (Colors.normalEm, Colors.Normal) + '\n')
411 413 out_string.extend(self._format_list(elist))
412 414 lines = self._format_exception_only(etype, value)
413 415 for line in lines[:-1]:
414 416 out_string.append(" "+line)
415 417 out_string.append(lines[-1])
416 418 return ''.join(out_string)
417 419
418 420 def _format_list(self, extracted_list):
419 421 """Format a list of traceback entry tuples for printing.
420 422
421 423 Given a list of tuples as returned by extract_tb() or
422 424 extract_stack(), return a list of strings ready for printing.
423 425 Each string in the resulting list corresponds to the item with the
424 426 same index in the argument list. Each string ends in a newline;
425 427 the strings may contain internal newlines as well, for those items
426 428 whose source text line is not None.
427 429
428 430 Lifted almost verbatim from traceback.py
429 431 """
430 432
431 433 Colors = self.Colors
432 434 list = []
433 435 for filename, lineno, name, line in extracted_list[:-1]:
434 436 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
435 437 (Colors.filename, filename, Colors.Normal,
436 438 Colors.lineno, lineno, Colors.Normal,
437 439 Colors.name, name, Colors.Normal)
438 440 if line:
439 441 item = item + ' %s\n' % line.strip()
440 442 list.append(item)
441 443 # Emphasize the last entry
442 444 filename, lineno, name, line = extracted_list[-1]
443 445 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
444 446 (Colors.normalEm,
445 447 Colors.filenameEm, filename, Colors.normalEm,
446 448 Colors.linenoEm, lineno, Colors.normalEm,
447 449 Colors.nameEm, name, Colors.normalEm,
448 450 Colors.Normal)
449 451 if line:
450 452 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
451 453 Colors.Normal)
452 454 list.append(item)
453 455 return list
454 456
455 457 def _format_exception_only(self, etype, value):
456 458 """Format the exception part of a traceback.
457 459
458 460 The arguments are the exception type and value such as given by
459 461 sys.exc_info()[:2]. The return value is a list of strings, each ending
460 462 in a newline. Normally, the list contains a single string; however,
461 463 for SyntaxError exceptions, it contains several lines that (when
462 464 printed) display detailed information about where the syntax error
463 465 occurred. The message indicating which exception occurred is the
464 466 always last string in the list.
465 467
466 468 Also lifted nearly verbatim from traceback.py
467 469 """
468 470
469 471 have_filedata = False
470 472 Colors = self.Colors
471 473 list = []
472 474 try:
473 475 stype = Colors.excName + etype.__name__ + Colors.Normal
474 476 except AttributeError:
475 477 stype = etype # String exceptions don't get special coloring
476 478 if value is None:
477 479 list.append( str(stype) + '\n')
478 480 else:
479 481 if etype is SyntaxError:
480 482 try:
481 483 msg, (filename, lineno, offset, line) = value
482 484 except:
483 485 have_filedata = False
484 486 else:
485 487 have_filedata = True
486 488 #print 'filename is',filename # dbg
487 489 if not filename: filename = "<string>"
488 490 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
489 491 (Colors.normalEm,
490 492 Colors.filenameEm, filename, Colors.normalEm,
491 493 Colors.linenoEm, lineno, Colors.Normal ))
492 494 if line is not None:
493 495 i = 0
494 496 while i < len(line) and line[i].isspace():
495 497 i = i+1
496 498 list.append('%s %s%s\n' % (Colors.line,
497 499 line.strip(),
498 500 Colors.Normal))
499 501 if offset is not None:
500 502 s = ' '
501 503 for c in line[i:offset-1]:
502 504 if c.isspace():
503 505 s = s + c
504 506 else:
505 507 s = s + ' '
506 508 list.append('%s%s^%s\n' % (Colors.caret, s,
507 509 Colors.Normal) )
508 510 value = msg
509 511 s = self._some_str(value)
510 512 if s:
511 513 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
512 514 Colors.Normal, s))
513 515 else:
514 516 list.append('%s\n' % str(stype))
515 517
516 518 # sync with user hooks
517 519 if have_filedata:
518 520 ipinst = ipapi.get()
519 521 if ipinst is not None:
520 522 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
521 523
522 524 return list
523 525
524 526 def show_exception_only(self, etype, value):
525 527 """Only print the exception type and message, without a traceback.
526 528
527 529 Parameters
528 530 ----------
529 531 etype : exception type
530 532 value : exception value
531 533 """
532 534 # This method needs to use __call__ from *this* class, not the one from
533 535 # a subclass whose signature or behavior may be different
534 536 Term.cout.flush()
535 537 ostream = sys.stdout if self.out_stream == 'stdout' else Term.cerr
536 print >> ostream, ListTB.text(self, etype, value, []),
538 ostream.write(ListTB.text(self, etype, value, []))
537 539 ostream.flush()
538 540
539 541 def _some_str(self, value):
540 542 # Lifted from traceback.py
541 543 try:
542 544 return str(value)
543 545 except:
544 546 return '<unprintable %s object>' % type(value).__name__
545 547
546 548 #----------------------------------------------------------------------------
547 549 class VerboseTB(TBTools):
548 550 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
549 551 of HTML. Requires inspect and pydoc. Crazy, man.
550 552
551 553 Modified version which optionally strips the topmost entries from the
552 554 traceback, to be used with alternate interpreters (because their own code
553 555 would appear in the traceback)."""
554 556
555 557 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
556 558 call_pdb = 0, include_vars=1):
557 559 """Specify traceback offset, headers and color scheme.
558 560
559 561 Define how many frames to drop from the tracebacks. Calling it with
560 562 tb_offset=1 allows use of this handler in interpreters which will have
561 563 their own code at the top of the traceback (VerboseTB will first
562 564 remove that frame before printing the traceback info)."""
563 565 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
564 566 self.tb_offset = tb_offset
565 567 self.long_header = long_header
566 568 self.include_vars = include_vars
567 569
568 570 def text(self, etype, evalue, etb, context=5):
569 571 """Return a nice text document describing the traceback."""
570 572
571 573 # some locals
572 574 try:
573 575 etype = etype.__name__
574 576 except AttributeError:
575 577 pass
576 578 Colors = self.Colors # just a shorthand + quicker name lookup
577 579 ColorsNormal = Colors.Normal # used a lot
578 580 col_scheme = self.color_scheme_table.active_scheme_name
579 581 indent = ' '*INDENT_SIZE
580 582 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
581 583 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
582 584 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
583 585
584 586 # some internal-use functions
585 587 def text_repr(value):
586 588 """Hopefully pretty robust repr equivalent."""
587 589 # this is pretty horrible but should always return *something*
588 590 try:
589 591 return pydoc.text.repr(value)
590 592 except KeyboardInterrupt:
591 593 raise
592 594 except:
593 595 try:
594 596 return repr(value)
595 597 except KeyboardInterrupt:
596 598 raise
597 599 except:
598 600 try:
599 601 # all still in an except block so we catch
600 602 # getattr raising
601 603 name = getattr(value, '__name__', None)
602 604 if name:
603 605 # ick, recursion
604 606 return text_repr(name)
605 607 klass = getattr(value, '__class__', None)
606 608 if klass:
607 609 return '%s instance' % text_repr(klass)
608 610 except KeyboardInterrupt:
609 611 raise
610 612 except:
611 613 return 'UNRECOVERABLE REPR FAILURE'
612 614 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
613 615 def nullrepr(value, repr=text_repr): return ''
614 616
615 617 # meat of the code begins
616 618 try:
617 619 etype = etype.__name__
618 620 except AttributeError:
619 621 pass
620 622
621 623 if self.long_header:
622 624 # Header with the exception type, python version, and date
623 625 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
624 626 date = time.ctime(time.time())
625 627
626 628 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
627 629 exc, ' '*(75-len(str(etype))-len(pyver)),
628 630 pyver, string.rjust(date, 75) )
629 631 head += "\nA problem occured executing Python code. Here is the sequence of function"\
630 632 "\ncalls leading up to the error, with the most recent (innermost) call last."
631 633 else:
632 634 # Simplified header
633 635 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
634 636 string.rjust('Traceback (most recent call last)',
635 637 75 - len(str(etype)) ) )
636 638 frames = []
637 639 # Flush cache before calling inspect. This helps alleviate some of the
638 640 # problems with python 2.3's inspect.py.
639 641 linecache.checkcache()
640 642 # Drop topmost frames if requested
641 643 try:
642 644 # Try the default getinnerframes and Alex's: Alex's fixes some
643 645 # problems, but it generates empty tracebacks for console errors
644 646 # (5 blanks lines) where none should be returned.
645 647 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
646 648 #print 'python records:', records # dbg
647 649 records = _fixed_getinnerframes(etb, context,self.tb_offset)
648 650 #print 'alex records:', records # dbg
649 651 except:
650 652
651 653 # FIXME: I've been getting many crash reports from python 2.3
652 654 # users, traceable to inspect.py. If I can find a small test-case
653 655 # to reproduce this, I should either write a better workaround or
654 656 # file a bug report against inspect (if that's the real problem).
655 657 # So far, I haven't been able to find an isolated example to
656 658 # reproduce the problem.
657 659 inspect_error()
658 660 traceback.print_exc(file=Term.cerr)
659 661 info('\nUnfortunately, your original traceback can not be constructed.\n')
660 662 return ''
661 663
662 664 # build some color string templates outside these nested loops
663 665 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
664 666 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
665 667 ColorsNormal)
666 668 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
667 669 (Colors.vName, Colors.valEm, ColorsNormal)
668 670 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
669 671 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
670 672 Colors.vName, ColorsNormal)
671 673 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
672 674 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
673 675 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
674 676 ColorsNormal)
675 677
676 678 # now, loop over all records printing context and info
677 679 abspath = os.path.abspath
678 680 for frame, file, lnum, func, lines, index in records:
679 681 #print '*** record:',file,lnum,func,lines,index # dbg
680 682 try:
681 683 file = file and abspath(file) or '?'
682 684 except OSError:
683 685 # if file is '<console>' or something not in the filesystem,
684 686 # the abspath call will throw an OSError. Just ignore it and
685 687 # keep the original file string.
686 688 pass
687 689 link = tpl_link % file
688 690 try:
689 691 args, varargs, varkw, locals = inspect.getargvalues(frame)
690 692 except:
691 693 # This can happen due to a bug in python2.3. We should be
692 694 # able to remove this try/except when 2.4 becomes a
693 695 # requirement. Bug details at http://python.org/sf/1005466
694 696 inspect_error()
695 697 traceback.print_exc(file=Term.cerr)
696 698 info("\nIPython's exception reporting continues...\n")
697 699
698 700 if func == '?':
699 701 call = ''
700 702 else:
701 703 # Decide whether to include variable details or not
702 704 var_repr = self.include_vars and eqrepr or nullrepr
703 705 try:
704 706 call = tpl_call % (func,inspect.formatargvalues(args,
705 707 varargs, varkw,
706 708 locals,formatvalue=var_repr))
707 709 except KeyError:
708 710 # Very odd crash from inspect.formatargvalues(). The
709 711 # scenario under which it appeared was a call to
710 712 # view(array,scale) in NumTut.view.view(), where scale had
711 713 # been defined as a scalar (it should be a tuple). Somehow
712 714 # inspect messes up resolving the argument list of view()
713 715 # and barfs out. At some point I should dig into this one
714 716 # and file a bug report about it.
715 717 inspect_error()
716 718 traceback.print_exc(file=Term.cerr)
717 719 info("\nIPython's exception reporting continues...\n")
718 720 call = tpl_call_fail % func
719 721
720 722 # Initialize a list of names on the current line, which the
721 723 # tokenizer below will populate.
722 724 names = []
723 725
724 726 def tokeneater(token_type, token, start, end, line):
725 727 """Stateful tokeneater which builds dotted names.
726 728
727 729 The list of names it appends to (from the enclosing scope) can
728 730 contain repeated composite names. This is unavoidable, since
729 731 there is no way to disambguate partial dotted structures until
730 732 the full list is known. The caller is responsible for pruning
731 733 the final list of duplicates before using it."""
732 734
733 735 # build composite names
734 736 if token == '.':
735 737 try:
736 738 names[-1] += '.'
737 739 # store state so the next token is added for x.y.z names
738 740 tokeneater.name_cont = True
739 741 return
740 742 except IndexError:
741 743 pass
742 744 if token_type == tokenize.NAME and token not in keyword.kwlist:
743 745 if tokeneater.name_cont:
744 746 # Dotted names
745 747 names[-1] += token
746 748 tokeneater.name_cont = False
747 749 else:
748 750 # Regular new names. We append everything, the caller
749 751 # will be responsible for pruning the list later. It's
750 752 # very tricky to try to prune as we go, b/c composite
751 753 # names can fool us. The pruning at the end is easy
752 754 # to do (or the caller can print a list with repeated
753 755 # names if so desired.
754 756 names.append(token)
755 757 elif token_type == tokenize.NEWLINE:
756 758 raise IndexError
757 759 # we need to store a bit of state in the tokenizer to build
758 760 # dotted names
759 761 tokeneater.name_cont = False
760 762
761 763 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
762 764 line = getline(file, lnum[0])
763 765 lnum[0] += 1
764 766 return line
765 767
766 768 # Build the list of names on this line of code where the exception
767 769 # occurred.
768 770 try:
769 771 # This builds the names list in-place by capturing it from the
770 772 # enclosing scope.
771 773 tokenize.tokenize(linereader, tokeneater)
772 774 except IndexError:
773 775 # signals exit of tokenizer
774 776 pass
775 777 except tokenize.TokenError,msg:
776 778 _m = ("An unexpected error occurred while tokenizing input\n"
777 779 "The following traceback may be corrupted or invalid\n"
778 780 "The error message is: %s\n" % msg)
779 781 error(_m)
780 782
781 783 # prune names list of duplicates, but keep the right order
782 784 unique_names = uniq_stable(names)
783 785
784 786 # Start loop over vars
785 787 lvals = []
786 788 if self.include_vars:
787 789 for name_full in unique_names:
788 790 name_base = name_full.split('.',1)[0]
789 791 if name_base in frame.f_code.co_varnames:
790 792 if locals.has_key(name_base):
791 793 try:
792 794 value = repr(eval(name_full,locals))
793 795 except:
794 796 value = undefined
795 797 else:
796 798 value = undefined
797 799 name = tpl_local_var % name_full
798 800 else:
799 801 if frame.f_globals.has_key(name_base):
800 802 try:
801 803 value = repr(eval(name_full,frame.f_globals))
802 804 except:
803 805 value = undefined
804 806 else:
805 807 value = undefined
806 808 name = tpl_global_var % name_full
807 809 lvals.append(tpl_name_val % (name,value))
808 810 if lvals:
809 811 lvals = '%s%s' % (indent,em_normal.join(lvals))
810 812 else:
811 813 lvals = ''
812 814
813 815 level = '%s %s\n' % (link,call)
814 816
815 817 if index is None:
816 818 frames.append(level)
817 819 else:
818 820 frames.append('%s%s' % (level,''.join(
819 821 _format_traceback_lines(lnum,index,lines,Colors,lvals,
820 822 col_scheme))))
821 823
822 824 # Get (safely) a string form of the exception info
823 825 try:
824 826 etype_str,evalue_str = map(str,(etype,evalue))
825 827 except:
826 828 # User exception is improperly defined.
827 829 etype,evalue = str,sys.exc_info()[:2]
828 830 etype_str,evalue_str = map(str,(etype,evalue))
829 831 # ... and format it
830 832 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
831 833 ColorsNormal, evalue_str)]
832 834 if type(evalue) is types.InstanceType:
833 835 try:
834 836 names = [w for w in dir(evalue) if isinstance(w, basestring)]
835 837 except:
836 838 # Every now and then, an object with funny inernals blows up
837 839 # when dir() is called on it. We do the best we can to report
838 840 # the problem and continue
839 841 _m = '%sException reporting error (object with broken dir())%s:'
840 842 exception.append(_m % (Colors.excName,ColorsNormal))
841 843 etype_str,evalue_str = map(str,sys.exc_info()[:2])
842 844 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
843 845 ColorsNormal, evalue_str))
844 846 names = []
845 847 for name in names:
846 848 value = text_repr(getattr(evalue, name))
847 849 exception.append('\n%s%s = %s' % (indent, name, value))
848 850
849 851 # vds: >>
850 852 if records:
851 853 filepath, lnum = records[-1][1:3]
852 854 #print "file:", str(file), "linenb", str(lnum) # dbg
853 855 filepath = os.path.abspath(filepath)
854 856 ipinst = ipapi.get()
855 857 if ipinst is not None:
856 858 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
857 859 # vds: <<
858 860
859 861 # return all our info assembled as a single string
860 862 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
861 863
862 864 def debugger(self,force=False):
863 865 """Call up the pdb debugger if desired, always clean up the tb
864 866 reference.
865 867
866 868 Keywords:
867 869
868 870 - force(False): by default, this routine checks the instance call_pdb
869 871 flag and does not actually invoke the debugger if the flag is false.
870 872 The 'force' option forces the debugger to activate even if the flag
871 873 is false.
872 874
873 875 If the call_pdb flag is set, the pdb interactive debugger is
874 876 invoked. In all cases, the self.tb reference to the current traceback
875 877 is deleted to prevent lingering references which hamper memory
876 878 management.
877 879
878 880 Note that each call to pdb() does an 'import readline', so if your app
879 881 requires a special setup for the readline completers, you'll have to
880 882 fix that by hand after invoking the exception handler."""
881 883
882 884 if force or self.call_pdb:
883 885 if self.pdb is None:
884 886 self.pdb = debugger.Pdb(
885 887 self.color_scheme_table.active_scheme_name)
886 888 # the system displayhook may have changed, restore the original
887 889 # for pdb
888 890 display_trap = DisplayTrap(None, sys.__displayhook__)
889 891 with display_trap:
890 892 self.pdb.reset()
891 893 # Find the right frame so we don't pop up inside ipython itself
892 894 if hasattr(self,'tb') and self.tb is not None:
893 895 etb = self.tb
894 896 else:
895 897 etb = self.tb = sys.last_traceback
896 898 while self.tb is not None and self.tb.tb_next is not None:
897 899 self.tb = self.tb.tb_next
898 900 if etb and etb.tb_next:
899 901 etb = etb.tb_next
900 902 self.pdb.botframe = etb.tb_frame
901 903 self.pdb.interaction(self.tb.tb_frame, self.tb)
902 904
903 905 if hasattr(self,'tb'):
904 906 del self.tb
905 907
906 908 def handler(self, info=None):
907 909 (etype, evalue, etb) = info or sys.exc_info()
908 910 self.tb = etb
909 911 Term.cout.flush()
910 print >> Term.cerr, self.text(etype, evalue, etb)
911 Term.cerr.flush()
912 Term.cerr.writeln(self.text(etype, evalue, etb))
912 913
913 914 # Changed so an instance can just be called as VerboseTB_inst() and print
914 915 # out the right info on its own.
915 916 def __call__(self, etype=None, evalue=None, etb=None):
916 917 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
917 918 if etb is None:
918 919 self.handler()
919 920 else:
920 921 self.handler((etype, evalue, etb))
921 922 try:
922 923 self.debugger()
923 924 except KeyboardInterrupt:
924 925 print "\nKeyboardInterrupt"
925 926
926 927 #----------------------------------------------------------------------------
927 928 class FormattedTB(VerboseTB,ListTB):
928 929 """Subclass ListTB but allow calling with a traceback.
929 930
930 931 It can thus be used as a sys.excepthook for Python > 2.1.
931 932
932 933 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
933 934
934 935 Allows a tb_offset to be specified. This is useful for situations where
935 936 one needs to remove a number of topmost frames from the traceback (such as
936 937 occurs with python programs that themselves execute other python code,
937 938 like Python shells). """
938 939
939 940 def __init__(self, mode = 'Plain', color_scheme='Linux',
940 941 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
941 942
942 943 # NEVER change the order of this list. Put new modes at the end:
943 944 self.valid_modes = ['Plain','Context','Verbose']
944 945 self.verbose_modes = self.valid_modes[1:3]
945 946
946 947 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
947 948 call_pdb=call_pdb,include_vars=include_vars)
948 949 self.set_mode(mode)
949 950
950 951 def _extract_tb(self,tb):
951 952 if tb:
952 953 return traceback.extract_tb(tb)
953 954 else:
954 955 return None
955 956
956 957 def text(self, etype, value, tb,context=5,mode=None):
957 958 """Return formatted traceback.
958 959
959 960 If the optional mode parameter is given, it overrides the current
960 961 mode."""
961 962
962 963 if mode is None:
963 964 mode = self.mode
964 965 if mode in self.verbose_modes:
965 966 # verbose modes need a full traceback
966 967 return VerboseTB.text(self,etype, value, tb,context=5)
967 968 else:
968 969 # We must check the source cache because otherwise we can print
969 970 # out-of-date source code.
970 971 linecache.checkcache()
971 972 # Now we can extract and format the exception
972 973 elist = self._extract_tb(tb)
973 974 if len(elist) > self.tb_offset:
974 975 del elist[:self.tb_offset]
975 976 return ListTB.text(self,etype,value,elist)
976 977
977 978 def set_mode(self,mode=None):
978 979 """Switch to the desired mode.
979 980
980 981 If mode is not specified, cycles through the available modes."""
981 982
982 983 if not mode:
983 984 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
984 985 len(self.valid_modes)
985 986 self.mode = self.valid_modes[new_idx]
986 987 elif mode not in self.valid_modes:
987 988 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
988 989 'Valid modes: '+str(self.valid_modes)
989 990 else:
990 991 self.mode = mode
991 992 # include variable details only in 'Verbose' mode
992 993 self.include_vars = (self.mode == self.valid_modes[2])
993 994
994 995 # some convenient shorcuts
995 996 def plain(self):
996 997 self.set_mode(self.valid_modes[0])
997 998
998 999 def context(self):
999 1000 self.set_mode(self.valid_modes[1])
1000 1001
1001 1002 def verbose(self):
1002 1003 self.set_mode(self.valid_modes[2])
1003 1004
1004 1005 #----------------------------------------------------------------------------
1005 1006 class AutoFormattedTB(FormattedTB):
1006 1007 """A traceback printer which can be called on the fly.
1007 1008
1008 1009 It will find out about exceptions by itself.
1009 1010
1010 1011 A brief example:
1011 1012
1012 1013 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1013 1014 try:
1014 1015 ...
1015 1016 except:
1016 1017 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1017 1018 """
1018 1019
1019 1020 def __call__(self,etype=None,evalue=None,etb=None,
1020 1021 out=None,tb_offset=None):
1021 1022 """Print out a formatted exception traceback.
1022 1023
1023 1024 Optional arguments:
1024 1025 - out: an open file-like object to direct output to.
1025 1026
1026 1027 - tb_offset: the number of frames to skip over in the stack, on a
1027 1028 per-call basis (this overrides temporarily the instance's tb_offset
1028 1029 given at initialization time. """
1029 1030
1030 1031 if out is None:
1031 1032 out = sys.stdout if self.out_stream=='stdout' else self.out_stream
1032 1033 Term.cout.flush()
1033 1034 if tb_offset is not None:
1034 1035 tb_offset, self.tb_offset = self.tb_offset, tb_offset
1035 print >> out, self.text(etype, evalue, etb)
1036 out.write(self.text(etype, evalue, etb))
1037 out.write('\n')
1036 1038 self.tb_offset = tb_offset
1037 1039 else:
1038 print >> out, self.text(etype, evalue, etb)
1040 out.write(self.text(etype, evalue, etb))
1041 out.write('\n')
1039 1042 out.flush()
1040 1043 try:
1041 1044 self.debugger()
1042 1045 except KeyboardInterrupt:
1043 1046 print "\nKeyboardInterrupt"
1044 1047
1045 1048 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1046 1049 if etype is None:
1047 1050 etype,value,tb = sys.exc_info()
1048 1051 self.tb = tb
1049 1052 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1050 1053
1051 1054 #---------------------------------------------------------------------------
1052 1055 # A simple class to preserve Nathan's original functionality.
1053 1056 class ColorTB(FormattedTB):
1054 1057 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1055 1058 def __init__(self,color_scheme='Linux',call_pdb=0):
1056 1059 FormattedTB.__init__(self,color_scheme=color_scheme,
1057 1060 call_pdb=call_pdb)
1058 1061
1059 1062 #----------------------------------------------------------------------------
1060 1063 # module testing (minimal)
1061 1064 if __name__ == "__main__":
1062 1065 def spam(c, (d, e)):
1063 1066 x = c + d
1064 1067 y = c * d
1065 1068 foo(x, y)
1066 1069
1067 1070 def foo(a, b, bar=1):
1068 1071 eggs(a, b + bar)
1069 1072
1070 1073 def eggs(f, g, z=globals()):
1071 1074 h = f + g
1072 1075 i = f - g
1073 1076 return h / i
1074 1077
1075 1078 print ''
1076 1079 print '*** Before ***'
1077 1080 try:
1078 1081 print spam(1, (2, 3))
1079 1082 except:
1080 1083 traceback.print_exc()
1081 1084 print ''
1082 1085
1083 1086 handler = ColorTB()
1084 1087 print '*** ColorTB ***'
1085 1088 try:
1086 1089 print spam(1, (2, 3))
1087 1090 except:
1088 1091 apply(handler, sys.exc_info() )
1089 1092 print ''
1090 1093
1091 1094 handler = VerboseTB()
1092 1095 print '*** VerboseTB ***'
1093 1096 try:
1094 1097 print spam(1, (2, 3))
1095 1098 except:
1096 1099 apply(handler, sys.exc_info() )
1097 1100 print ''
1098 1101
General Comments 0
You need to be logged in to leave comments. Login now