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