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