##// END OF EJS Templates
Refactor simplify and share common function.
Matthias Bussonnier -
Show More
@@ -1,632 +1,633 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 http://www.python.org/2.2.3/license.html"""
17 17
18 18 #*****************************************************************************
19 19 #
20 20 # This file is licensed under the PSF license.
21 21 #
22 22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 24 #
25 25 #
26 26 #*****************************************************************************
27 27 from __future__ import print_function
28 28
29 29 import bdb
30 30 import functools
31 31 import inspect
32 32 import sys
33 33
34 34 from IPython import get_ipython
35 35 from IPython.utils import PyColorize, ulinecache
36 36 from IPython.utils import coloransi, io, py3compat
37 37 from IPython.core.excolors import exception_colors
38 38 from IPython.testing.skipdoctest import skip_doctest
39 39
40 40 # See if we can use pydb.
41 41 has_pydb = False
42 42 prompt = 'ipdb> '
43 43 #We have to check this directly from sys.argv, config struct not yet available
44 44 if '--pydb' in sys.argv:
45 45 try:
46 46 import pydb
47 47 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
48 48 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
49 49 # better protect against it.
50 50 has_pydb = True
51 51 except ImportError:
52 52 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
53 53
54 54 if has_pydb:
55 55 from pydb import Pdb as OldPdb
56 56 prompt = 'ipydb> '
57 57 else:
58 58 from pdb import Pdb as OldPdb
59 59
60 60 # Allow the set_trace code to operate outside of an ipython instance, even if
61 61 # it does so with some limitations. The rest of this support is implemented in
62 62 # the Tracer constructor.
63
64 def make_arrow(pad):
65 """generate the leading arrow in front of traceback or debugger"""
66 if pad >= 2:
67 return '-'*(pad-2) + '> '
68 elif pad == 1:
69 return '>'
70 return ''
71
72
63 73 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
64 74 """Exception hook which handles `BdbQuit` exceptions.
65 75
66 76 All other exceptions are processed using the `excepthook`
67 77 parameter.
68 78 """
69 79 if et==bdb.BdbQuit:
70 80 print('Exiting Debugger.')
71 81 elif excepthook is not None:
72 82 excepthook(et, ev, tb)
73 83 else:
74 84 # Backwards compatibility. Raise deprecation warning?
75 85 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
76 86
77 87 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
78 88 print('Exiting Debugger.')
79 89
80 90
81 91 class Tracer(object):
82 92 """Class for local debugging, similar to pdb.set_trace.
83 93
84 94 Instances of this class, when called, behave like pdb.set_trace, but
85 95 providing IPython's enhanced capabilities.
86 96
87 97 This is implemented as a class which must be initialized in your own code
88 98 and not as a standalone function because we need to detect at runtime
89 99 whether IPython is already active or not. That detection is done in the
90 100 constructor, ensuring that this code plays nicely with a running IPython,
91 101 while functioning acceptably (though with limitations) if outside of it.
92 102 """
93 103
94 104 @skip_doctest
95 105 def __init__(self, colors=None):
96 106 """Create a local debugger instance.
97 107
98 108 Parameters
99 109 ----------
100 110
101 111 colors : str, optional
102 112 The name of the color scheme to use, it must be one of IPython's
103 113 valid color schemes. If not given, the function will default to
104 114 the current IPython scheme when running inside IPython, and to
105 115 'NoColor' otherwise.
106 116
107 117 Examples
108 118 --------
109 119 ::
110 120
111 121 from IPython.core.debugger import Tracer; debug_here = Tracer()
112 122
113 123 Later in your code::
114 124
115 125 debug_here() # -> will open up the debugger at that point.
116 126
117 127 Once the debugger activates, you can use all of its regular commands to
118 128 step through code, set breakpoints, etc. See the pdb documentation
119 129 from the Python standard library for usage details.
120 130 """
121 131
122 132 ip = get_ipython()
123 133 if ip is None:
124 134 # Outside of ipython, we set our own exception hook manually
125 135 sys.excepthook = functools.partial(BdbQuit_excepthook,
126 136 excepthook=sys.excepthook)
127 137 def_colors = 'NoColor'
128 138 try:
129 139 # Limited tab completion support
130 140 import readline
131 141 readline.parse_and_bind('tab: complete')
132 142 except ImportError:
133 143 pass
134 144 else:
135 145 # In ipython, we use its custom exception handler mechanism
136 146 def_colors = ip.colors
137 147 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
138 148
139 149 if colors is None:
140 150 colors = def_colors
141 151
142 152 # The stdlib debugger internally uses a modified repr from the `repr`
143 153 # module, that limits the length of printed strings to a hardcoded
144 154 # limit of 30 characters. That much trimming is too aggressive, let's
145 155 # at least raise that limit to 80 chars, which should be enough for
146 156 # most interactive uses.
147 157 try:
148 158 try:
149 159 from reprlib import aRepr # Py 3
150 160 except ImportError:
151 161 from repr import aRepr # Py 2
152 162 aRepr.maxstring = 80
153 163 except:
154 164 # This is only a user-facing convenience, so any error we encounter
155 165 # here can be warned about but can be otherwise ignored. These
156 166 # printouts will tell us about problems if this API changes
157 167 import traceback
158 168 traceback.print_exc()
159 169
160 170 self.debugger = Pdb(colors)
161 171
162 172 def __call__(self):
163 173 """Starts an interactive debugger at the point where called.
164 174
165 175 This is similar to the pdb.set_trace() function from the std lib, but
166 176 using IPython's enhanced debugger."""
167 177
168 178 self.debugger.set_trace(sys._getframe().f_back)
169 179
170 180
171 181 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
172 182 """Make new_fn have old_fn's doc string. This is particularly useful
173 183 for the ``do_...`` commands that hook into the help system.
174 184 Adapted from from a comp.lang.python posting
175 185 by Duncan Booth."""
176 186 def wrapper(*args, **kw):
177 187 return new_fn(*args, **kw)
178 188 if old_fn.__doc__:
179 189 wrapper.__doc__ = old_fn.__doc__ + additional_text
180 190 return wrapper
181 191
182 192
183 193 def _file_lines(fname):
184 194 """Return the contents of a named file as a list of lines.
185 195
186 196 This function never raises an IOError exception: if the file can't be
187 197 read, it simply returns an empty list."""
188 198
189 199 try:
190 200 outfile = open(fname)
191 201 except IOError:
192 202 return []
193 203 else:
194 204 out = outfile.readlines()
195 205 outfile.close()
196 206 return out
197 207
198 208
199 209 class Pdb(OldPdb):
200 210 """Modified Pdb class, does not load readline."""
201 211
202 212 def __init__(self,color_scheme='NoColor',completekey=None,
203 213 stdin=None, stdout=None, context=5):
204 214
205 215 # Parent constructor:
206 216 try:
207 217 self.context=int(context)
208 218 if self.context <= 0:
209 219 raise ValueError("Context must be a positive integer")
210 220 except (TypeError, ValueError):
211 221 raise ValueError("Context must be a positive integer")
212 222
213 223 if has_pydb and completekey is None:
214 224 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
215 225 else:
216 226 OldPdb.__init__(self,completekey,stdin,stdout)
217 227
218 228 # IPython changes...
219 229 self.is_pydb = has_pydb
220 230
221 231 self.shell = get_ipython()
222 232
223 233 if self.shell is None:
224 234 # No IPython instance running, we must create one
225 235 from IPython.terminal.interactiveshell import \
226 236 TerminalInteractiveShell
227 237 self.shell = TerminalInteractiveShell.instance()
228 238
229 239 if self.is_pydb:
230 240
231 241 # interactiveshell.py's ipalias seems to want pdb's checkline
232 242 # which located in pydb.fn
233 243 import pydb.fns
234 244 self.checkline = lambda filename, lineno: \
235 245 pydb.fns.checkline(self, filename, lineno)
236 246
237 247 self.curframe = None
238 248 self.do_restart = self.new_do_restart
239 249
240 250 self.old_all_completions = self.shell.Completer.all_completions
241 251 self.shell.Completer.all_completions=self.all_completions
242 252
243 253 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
244 254 OldPdb.do_list)
245 255 self.do_l = self.do_list
246 256 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
247 257 OldPdb.do_frame)
248 258
249 259 self.aliases = {}
250 260
251 261 # Create color table: we copy the default one from the traceback
252 262 # module and add a few attributes needed for debugging
253 263 self.color_scheme_table = exception_colors()
254 264
255 265 # shorthands
256 266 C = coloransi.TermColors
257 267 cst = self.color_scheme_table
258 268
259 269 cst['NoColor'].colors.prompt = C.NoColor
260 270 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
261 271 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
262 272
263 273 cst['Linux'].colors.prompt = C.Green
264 274 cst['Linux'].colors.breakpoint_enabled = C.LightRed
265 275 cst['Linux'].colors.breakpoint_disabled = C.Red
266 276
267 277 cst['LightBG'].colors.prompt = C.Blue
268 278 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 279 cst['LightBG'].colors.breakpoint_disabled = C.Red
270 280
271 281 self.set_colors(color_scheme)
272 282
273 283 # Add a python parser so we can syntax highlight source while
274 284 # debugging.
275 285 self.parser = PyColorize.Parser()
276 286
277 287 # Set the prompt
278 288 Colors = cst.active_colors
279 289 self.prompt = u'%s%s%s' % (Colors.prompt, prompt, Colors.Normal) # The default prompt is '(Pdb)'
280 290
281 291 def set_colors(self, scheme):
282 292 """Shorthand access to the color table scheme selector method."""
283 293 self.color_scheme_table.set_active_scheme(scheme)
284 294
285 295 def interaction(self, frame, traceback):
286 296 self.shell.set_completer_frame(frame)
287 297 while True:
288 298 try:
289 299 OldPdb.interaction(self, frame, traceback)
290 300 break
291 301 except KeyboardInterrupt:
292 302 self.shell.write('\n' + self.shell.get_exception_only())
293 303 break
294 304 finally:
295 305 # Pdb sets readline delimiters, so set them back to our own
296 306 if self.shell.readline is not None:
297 307 self.shell.readline.set_completer_delims(self.shell.readline_delims)
298 308
299 309 def new_do_up(self, arg):
300 310 OldPdb.do_up(self, arg)
301 311 self.shell.set_completer_frame(self.curframe)
302 312 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
303 313
304 314 def new_do_down(self, arg):
305 315 OldPdb.do_down(self, arg)
306 316 self.shell.set_completer_frame(self.curframe)
307 317
308 318 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
309 319
310 320 def new_do_frame(self, arg):
311 321 OldPdb.do_frame(self, arg)
312 322 self.shell.set_completer_frame(self.curframe)
313 323
314 324 def new_do_quit(self, arg):
315 325
316 326 if hasattr(self, 'old_all_completions'):
317 327 self.shell.Completer.all_completions=self.old_all_completions
318 328
319 329 return OldPdb.do_quit(self, arg)
320 330
321 331 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
322 332
323 333 def new_do_restart(self, arg):
324 334 """Restart command. In the context of ipython this is exactly the same
325 335 thing as 'quit'."""
326 336 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
327 337 return self.do_quit(arg)
328 338
329 339 def postloop(self):
330 340 self.shell.set_completer_frame(None)
331 341
332 342 def print_stack_trace(self, context=None):
333 343 if context is None:
334 344 context = self.context
335 345 try:
336 346 context=int(context)
337 347 if context <= 0:
338 348 raise ValueError("Context must be a positive integer")
339 349 except (TypeError, ValueError):
340 350 raise ValueError("Context must be a positive integer")
341 351 try:
342 352 for frame_lineno in self.stack:
343 353 self.print_stack_entry(frame_lineno, context=context)
344 354 except KeyboardInterrupt:
345 355 pass
346 356
347 357 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
348 358 context=None):
349 359 if context is None:
350 360 context = self.context
351 361 try:
352 362 context=int(context)
353 363 if context <= 0:
354 364 raise ValueError("Context must be a positive integer")
355 365 except (TypeError, ValueError):
356 366 raise ValueError("Context must be a positive integer")
357 367 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
358 368
359 369 # vds: >>
360 370 frame, lineno = frame_lineno
361 371 filename = frame.f_code.co_filename
362 372 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
363 373 # vds: <<
364 374
365 375 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
366 376 if context is None:
367 377 context = self.context
368 378 try:
369 379 context=int(context)
370 380 if context <= 0:
371 381 print("Context must be a positive integer")
372 382 except (TypeError, ValueError):
373 383 print("Context must be a positive integer")
374 384 try:
375 385 import reprlib # Py 3
376 386 except ImportError:
377 387 import repr as reprlib # Py 2
378 388
379 389 ret = []
380 390
381 391 Colors = self.color_scheme_table.active_colors
382 392 ColorsNormal = Colors.Normal
383 393 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
384 394 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
385 395 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
386 396 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
387 397 ColorsNormal)
388 398
389 399 frame, lineno = frame_lineno
390 400
391 401 return_value = ''
392 402 if '__return__' in frame.f_locals:
393 403 rv = frame.f_locals['__return__']
394 404 #return_value += '->'
395 405 return_value += reprlib.repr(rv) + '\n'
396 406 ret.append(return_value)
397 407
398 408 #s = filename + '(' + `lineno` + ')'
399 409 filename = self.canonic(frame.f_code.co_filename)
400 410 link = tpl_link % py3compat.cast_unicode(filename)
401 411
402 412 if frame.f_code.co_name:
403 413 func = frame.f_code.co_name
404 414 else:
405 415 func = "<lambda>"
406 416
407 417 call = ''
408 418 if func != '?':
409 419 if '__args__' in frame.f_locals:
410 420 args = reprlib.repr(frame.f_locals['__args__'])
411 421 else:
412 422 args = '()'
413 423 call = tpl_call % (func, args)
414 424
415 425 # The level info should be generated in the same format pdb uses, to
416 426 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
417 427 if frame is self.curframe:
418 428 ret.append('> ')
419 429 else:
420 430 ret.append(' ')
421 431 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
422 432
423 433 start = lineno - 1 - context//2
424 434 lines = ulinecache.getlines(filename)
425 435 start = min(start, len(lines) - context)
426 436 start = max(start, 0)
427 437 lines = lines[start : start + context]
428 438
429 439 for i,line in enumerate(lines):
430 440 show_arrow = (start + 1 + i == lineno)
431 441 linetpl = (frame is self.curframe or show_arrow) \
432 442 and tpl_line_em \
433 443 or tpl_line
434 444 ret.append(self.__format_line(linetpl, filename,
435 445 start + 1 + i, line,
436 446 arrow = show_arrow) )
437 447 return ''.join(ret)
438 448
439 449 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
440 450 bp_mark = ""
441 451 bp_mark_color = ""
442 452
443 453 scheme = self.color_scheme_table.active_scheme_name
444 454 new_line, err = self.parser.format2(line, 'str', scheme)
445 455 if not err: line = new_line
446 456
447 457 bp = None
448 458 if lineno in self.get_file_breaks(filename):
449 459 bps = self.get_breaks(filename, lineno)
450 460 bp = bps[-1]
451 461
452 462 if bp:
453 463 Colors = self.color_scheme_table.active_colors
454 464 bp_mark = str(bp.number)
455 465 bp_mark_color = Colors.breakpoint_enabled
456 466 if not bp.enabled:
457 467 bp_mark_color = Colors.breakpoint_disabled
458 468
459 469 numbers_width = 7
460 470 if arrow:
461 471 # This is the line with the error
462 472 pad = numbers_width - len(str(lineno)) - len(bp_mark)
463 if pad >= 3:
464 marker = '-'*(pad-3) + '-> '
465 elif pad == 2:
466 marker = '> '
467 elif pad == 1:
468 marker = '>'
469 else:
470 marker = ''
471 num = '%s%s' % (marker, str(lineno))
472 line = tpl_line % (bp_mark_color + bp_mark, num, line)
473 num = '%s%s' % (make_arrow(pad), str(lineno))
473 474 else:
474 475 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
475 line = tpl_line % (bp_mark_color + bp_mark, num, line)
476 476
477 return line
477 return tpl_line % (bp_mark_color + bp_mark, num, line)
478
478 479
479 480 def list_command_pydb(self, arg):
480 481 """List command to use if we have a newer pydb installed"""
481 482 filename, first, last = OldPdb.parse_list_cmd(self, arg)
482 483 if filename is not None:
483 484 self.print_list_lines(filename, first, last)
484 485
485 486 def print_list_lines(self, filename, first, last):
486 487 """The printing (as opposed to the parsing part of a 'list'
487 488 command."""
488 489 try:
489 490 Colors = self.color_scheme_table.active_colors
490 491 ColorsNormal = Colors.Normal
491 492 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
492 493 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
493 494 src = []
494 495 if filename == "<string>" and hasattr(self, "_exec_filename"):
495 496 filename = self._exec_filename
496 497
497 498 for lineno in range(first, last+1):
498 499 line = ulinecache.getline(filename, lineno)
499 500 if not line:
500 501 break
501 502
502 503 if lineno == self.curframe.f_lineno:
503 504 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
504 505 else:
505 506 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
506 507
507 508 src.append(line)
508 509 self.lineno = lineno
509 510
510 511 print(''.join(src), file=io.stdout)
511 512
512 513 except KeyboardInterrupt:
513 514 pass
514 515
515 516 def do_list(self, arg):
516 517 self.lastcmd = 'list'
517 518 last = None
518 519 if arg:
519 520 try:
520 521 x = eval(arg, {}, {})
521 522 if type(x) == type(()):
522 523 first, last = x
523 524 first = int(first)
524 525 last = int(last)
525 526 if last < first:
526 527 # Assume it's a count
527 528 last = first + last
528 529 else:
529 530 first = max(1, int(x) - 5)
530 531 except:
531 532 print('*** Error in argument:', repr(arg))
532 533 return
533 534 elif self.lineno is None:
534 535 first = max(1, self.curframe.f_lineno - 5)
535 536 else:
536 537 first = self.lineno + 1
537 538 if last is None:
538 539 last = first + 10
539 540 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
540 541
541 542 # vds: >>
542 543 lineno = first
543 544 filename = self.curframe.f_code.co_filename
544 545 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
545 546 # vds: <<
546 547
547 548 do_l = do_list
548 549
549 550 def getsourcelines(self, obj):
550 551 lines, lineno = inspect.findsource(obj)
551 552 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
552 553 # must be a module frame: do not try to cut a block out of it
553 554 return lines, 1
554 555 elif inspect.ismodule(obj):
555 556 return lines, 1
556 557 return inspect.getblock(lines[lineno:]), lineno+1
557 558
558 559 def do_longlist(self, arg):
559 560 self.lastcmd = 'longlist'
560 561 filename = self.curframe.f_code.co_filename
561 562 try:
562 563 lines, lineno = self.getsourcelines(self.curframe)
563 564 except OSError as err:
564 565 self.error(err)
565 566 return
566 567 last = lineno + len(lines)
567 568 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
568 569 do_ll = do_longlist
569 570
570 571 def do_pdef(self, arg):
571 572 """Print the call signature for any callable object.
572 573
573 574 The debugger interface to %pdef"""
574 575 namespaces = [('Locals', self.curframe.f_locals),
575 576 ('Globals', self.curframe.f_globals)]
576 577 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
577 578
578 579 def do_pdoc(self, arg):
579 580 """Print the docstring for an object.
580 581
581 582 The debugger interface to %pdoc."""
582 583 namespaces = [('Locals', self.curframe.f_locals),
583 584 ('Globals', self.curframe.f_globals)]
584 585 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
585 586
586 587 def do_pfile(self, arg):
587 588 """Print (or run through pager) the file where an object is defined.
588 589
589 590 The debugger interface to %pfile.
590 591 """
591 592 namespaces = [('Locals', self.curframe.f_locals),
592 593 ('Globals', self.curframe.f_globals)]
593 594 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
594 595
595 596 def do_pinfo(self, arg):
596 597 """Provide detailed information about an object.
597 598
598 599 The debugger interface to %pinfo, i.e., obj?."""
599 600 namespaces = [('Locals', self.curframe.f_locals),
600 601 ('Globals', self.curframe.f_globals)]
601 602 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
602 603
603 604 def do_pinfo2(self, arg):
604 605 """Provide extra detailed information about an object.
605 606
606 607 The debugger interface to %pinfo2, i.e., obj??."""
607 608 namespaces = [('Locals', self.curframe.f_locals),
608 609 ('Globals', self.curframe.f_globals)]
609 610 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
610 611
611 612 def do_psource(self, arg):
612 613 """Print (or run through pager) the source code for an object."""
613 614 namespaces = [('Locals', self.curframe.f_locals),
614 615 ('Globals', self.curframe.f_globals)]
615 616 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
616 617
617 618 if sys.version_info > (3, ):
618 619 def do_where(self, arg):
619 620 """w(here)
620 621 Print a stack trace, with the most recent frame at the bottom.
621 622 An arrow indicates the "current frame", which determines the
622 623 context of most commands. 'bt' is an alias for this command.
623 624
624 625 Take a number as argument as an (optional) number of context line to
625 626 print"""
626 627 if arg:
627 628 context = int(arg)
628 629 self.print_stack_trace(context)
629 630 else:
630 631 self.print_stack_trace()
631 632
632 633 do_w = do_where
@@ -1,1479 +1,1471 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 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 75 #*****************************************************************************
76 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 dis
87 87 import inspect
88 88 import keyword
89 89 import linecache
90 90 import os
91 91 import pydoc
92 92 import re
93 93 import sys
94 94 import time
95 95 import tokenize
96 96 import traceback
97 97 import types
98 98
99 99 try: # Python 2
100 100 generate_tokens = tokenize.generate_tokens
101 101 except AttributeError: # Python 3
102 102 generate_tokens = tokenize.tokenize
103 103
104 104 # For purposes of monkeypatching inspect to fix a bug in it.
105 105 from inspect import getsourcefile, getfile, getmodule, \
106 106 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
107 107
108 108 # IPython's own modules
109 109 # Modified pdb which doesn't damage IPython's readline handling
110 110 from IPython import get_ipython
111 111 from IPython.core import debugger
112 112 from IPython.core.display_trap import DisplayTrap
113 113 from IPython.core.excolors import exception_colors
114 114 from IPython.utils import PyColorize
115 115 from IPython.utils import io
116 116 from IPython.utils import openpy
117 117 from IPython.utils import path as util_path
118 118 from IPython.utils import py3compat
119 119 from IPython.utils import ulinecache
120 120 from IPython.utils.data import uniq_stable
121 121 from IPython.utils.warn import info, error
122 122
123 123 # Globals
124 124 # amount of space to put line numbers before verbose tracebacks
125 125 INDENT_SIZE = 8
126 126
127 127 # Default color scheme. This is used, for example, by the traceback
128 128 # formatter. When running in an actual IPython instance, the user's rc.colors
129 129 # value is used, but having a module global makes this functionality available
130 130 # to users of ultratb who are NOT running inside ipython.
131 131 DEFAULT_SCHEME = 'NoColor'
132 132
133 133 # ---------------------------------------------------------------------------
134 134 # Code begins
135 135
136 136 # Utility functions
137 137 def inspect_error():
138 138 """Print a message about internal inspect errors.
139 139
140 140 These are unfortunately quite common."""
141 141
142 142 error('Internal Python error in the inspect module.\n'
143 143 'Below is the traceback from this internal error.\n')
144 144
145 145
146 146 # This function is a monkeypatch we apply to the Python inspect module. We have
147 147 # now found when it's needed (see discussion on issue gh-1456), and we have a
148 148 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
149 149 # the monkeypatch is not applied. TK, Aug 2012.
150 150 def findsource(object):
151 151 """Return the entire source file and starting line number for an object.
152 152
153 153 The argument may be a module, class, method, function, traceback, frame,
154 154 or code object. The source code is returned as a list of all the lines
155 155 in the file and the line number indexes a line in that list. An IOError
156 156 is raised if the source code cannot be retrieved.
157 157
158 158 FIXED version with which we monkeypatch the stdlib to work around a bug."""
159 159
160 160 file = getsourcefile(object) or getfile(object)
161 161 # If the object is a frame, then trying to get the globals dict from its
162 162 # module won't work. Instead, the frame object itself has the globals
163 163 # dictionary.
164 164 globals_dict = None
165 165 if inspect.isframe(object):
166 166 # XXX: can this ever be false?
167 167 globals_dict = object.f_globals
168 168 else:
169 169 module = getmodule(object, file)
170 170 if module:
171 171 globals_dict = module.__dict__
172 172 lines = linecache.getlines(file, globals_dict)
173 173 if not lines:
174 174 raise IOError('could not get source code')
175 175
176 176 if ismodule(object):
177 177 return lines, 0
178 178
179 179 if isclass(object):
180 180 name = object.__name__
181 181 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
182 182 # make some effort to find the best matching class definition:
183 183 # use the one with the least indentation, which is the one
184 184 # that's most probably not inside a function definition.
185 185 candidates = []
186 186 for i in range(len(lines)):
187 187 match = pat.match(lines[i])
188 188 if match:
189 189 # if it's at toplevel, it's already the best one
190 190 if lines[i][0] == 'c':
191 191 return lines, i
192 192 # else add whitespace to candidate list
193 193 candidates.append((match.group(1), i))
194 194 if candidates:
195 195 # this will sort by whitespace, and by line number,
196 196 # less whitespace first
197 197 candidates.sort()
198 198 return lines, candidates[0][1]
199 199 else:
200 200 raise IOError('could not find class definition')
201 201
202 202 if ismethod(object):
203 203 object = object.__func__
204 204 if isfunction(object):
205 205 object = object.__code__
206 206 if istraceback(object):
207 207 object = object.tb_frame
208 208 if isframe(object):
209 209 object = object.f_code
210 210 if iscode(object):
211 211 if not hasattr(object, 'co_firstlineno'):
212 212 raise IOError('could not find function definition')
213 213 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
214 214 pmatch = pat.match
215 215 # fperez - fix: sometimes, co_firstlineno can give a number larger than
216 216 # the length of lines, which causes an error. Safeguard against that.
217 217 lnum = min(object.co_firstlineno, len(lines)) - 1
218 218 while lnum > 0:
219 219 if pmatch(lines[lnum]): break
220 220 lnum -= 1
221 221
222 222 return lines, lnum
223 223 raise IOError('could not find code object')
224 224
225 225
226 226 # This is a patched version of inspect.getargs that applies the (unmerged)
227 227 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
228 228 # https://github.com/ipython/ipython/issues/8205 and
229 229 # https://github.com/ipython/ipython/issues/8293
230 230 def getargs(co):
231 231 """Get information about the arguments accepted by a code object.
232 232
233 233 Three things are returned: (args, varargs, varkw), where 'args' is
234 234 a list of argument names (possibly containing nested lists), and
235 235 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
236 236 if not iscode(co):
237 237 raise TypeError('{!r} is not a code object'.format(co))
238 238
239 239 nargs = co.co_argcount
240 240 names = co.co_varnames
241 241 args = list(names[:nargs])
242 242 step = 0
243 243
244 244 # The following acrobatics are for anonymous (tuple) arguments.
245 245 for i in range(nargs):
246 246 if args[i][:1] in ('', '.'):
247 247 stack, remain, count = [], [], []
248 248 while step < len(co.co_code):
249 249 op = ord(co.co_code[step])
250 250 step = step + 1
251 251 if op >= dis.HAVE_ARGUMENT:
252 252 opname = dis.opname[op]
253 253 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
254 254 step = step + 2
255 255 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
256 256 remain.append(value)
257 257 count.append(value)
258 258 elif opname in ('STORE_FAST', 'STORE_DEREF'):
259 259 if op in dis.haslocal:
260 260 stack.append(co.co_varnames[value])
261 261 elif op in dis.hasfree:
262 262 stack.append((co.co_cellvars + co.co_freevars)[value])
263 263 # Special case for sublists of length 1: def foo((bar))
264 264 # doesn't generate the UNPACK_TUPLE bytecode, so if
265 265 # `remain` is empty here, we have such a sublist.
266 266 if not remain:
267 267 stack[0] = [stack[0]]
268 268 break
269 269 else:
270 270 remain[-1] = remain[-1] - 1
271 271 while remain[-1] == 0:
272 272 remain.pop()
273 273 size = count.pop()
274 274 stack[-size:] = [stack[-size:]]
275 275 if not remain: break
276 276 remain[-1] = remain[-1] - 1
277 277 if not remain: break
278 278 args[i] = stack[0]
279 279
280 280 varargs = None
281 281 if co.co_flags & inspect.CO_VARARGS:
282 282 varargs = co.co_varnames[nargs]
283 283 nargs = nargs + 1
284 284 varkw = None
285 285 if co.co_flags & inspect.CO_VARKEYWORDS:
286 286 varkw = co.co_varnames[nargs]
287 287 return inspect.Arguments(args, varargs, varkw)
288 288
289 289
290 290 # Monkeypatch inspect to apply our bugfix.
291 291 def with_patch_inspect(f):
292 292 """decorator for monkeypatching inspect.findsource"""
293 293
294 294 def wrapped(*args, **kwargs):
295 295 save_findsource = inspect.findsource
296 296 save_getargs = inspect.getargs
297 297 inspect.findsource = findsource
298 298 inspect.getargs = getargs
299 299 try:
300 300 return f(*args, **kwargs)
301 301 finally:
302 302 inspect.findsource = save_findsource
303 303 inspect.getargs = save_getargs
304 304
305 305 return wrapped
306 306
307 307
308 308 if py3compat.PY3:
309 309 fixed_getargvalues = inspect.getargvalues
310 310 else:
311 311 # Fixes for https://github.com/ipython/ipython/issues/8293
312 312 # and https://github.com/ipython/ipython/issues/8205.
313 313 # The relevant bug is caused by failure to correctly handle anonymous tuple
314 314 # unpacking, which only exists in Python 2.
315 315 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
316 316
317 317
318 318 def fix_frame_records_filenames(records):
319 319 """Try to fix the filenames in each record from inspect.getinnerframes().
320 320
321 321 Particularly, modules loaded from within zip files have useless filenames
322 322 attached to their code object, and inspect.getinnerframes() just uses it.
323 323 """
324 324 fixed_records = []
325 325 for frame, filename, line_no, func_name, lines, index in records:
326 326 # Look inside the frame's globals dictionary for __file__,
327 327 # which should be better. However, keep Cython filenames since
328 328 # we prefer the source filenames over the compiled .so file.
329 329 filename = py3compat.cast_unicode_py2(filename, "utf-8")
330 330 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
331 331 better_fn = frame.f_globals.get('__file__', None)
332 332 if isinstance(better_fn, str):
333 333 # Check the type just in case someone did something weird with
334 334 # __file__. It might also be None if the error occurred during
335 335 # import.
336 336 filename = better_fn
337 337 fixed_records.append((frame, filename, line_no, func_name, lines, index))
338 338 return fixed_records
339 339
340 340
341 341 @with_patch_inspect
342 342 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
343 343 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
344 344
345 345 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
346 346 # If the error is at the console, don't build any context, since it would
347 347 # otherwise produce 5 blank lines printed out (there is no file at the
348 348 # console)
349 349 rec_check = records[tb_offset:]
350 350 try:
351 351 rname = rec_check[0][1]
352 352 if rname == '<ipython console>' or rname.endswith('<string>'):
353 353 return rec_check
354 354 except IndexError:
355 355 pass
356 356
357 357 aux = traceback.extract_tb(etb)
358 358 assert len(records) == len(aux)
359 359 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
360 360 maybeStart = lnum - 1 - context // 2
361 361 start = max(maybeStart, 0)
362 362 end = start + context
363 363 lines = ulinecache.getlines(file)[start:end]
364 364 buf = list(records[i])
365 365 buf[LNUM_POS] = lnum
366 366 buf[INDEX_POS] = lnum - 1 - start
367 367 buf[LINES_POS] = lines
368 368 records[i] = tuple(buf)
369 369 return records[tb_offset:]
370 370
371 371 # Helper function -- largely belongs to VerboseTB, but we need the same
372 372 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
373 373 # can be recognized properly by ipython.el's py-traceback-line-re
374 374 # (SyntaxErrors have to be treated specially because they have no traceback)
375 375
376 376 _parser = PyColorize.Parser()
377 377
378 378
379 379 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
380 380 numbers_width = INDENT_SIZE - 1
381 381 res = []
382 382 i = lnum - index
383 383
384 384 # This lets us get fully syntax-highlighted tracebacks.
385 385 if scheme is None:
386 386 ipinst = get_ipython()
387 387 if ipinst is not None:
388 388 scheme = ipinst.colors
389 389 else:
390 390 scheme = DEFAULT_SCHEME
391 391
392 392 _line_format = _parser.format2
393 393
394 394 for line in lines:
395 395 line = py3compat.cast_unicode(line)
396 396
397 397 new_line, err = _line_format(line, 'str', scheme)
398 398 if not err: line = new_line
399 399
400 400 if i == lnum:
401 401 # This is the line with the error
402 402 pad = numbers_width - len(str(i))
403 if pad >= 3:
404 marker = '-' * (pad - 3) + '-> '
405 elif pad == 2:
406 marker = '> '
407 elif pad == 1:
408 marker = '>'
409 else:
410 marker = ''
411 num = marker + str(i)
403 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
412 404 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
413 405 Colors.line, line, Colors.Normal)
414 406 else:
415 407 num = '%*s' % (numbers_width, i)
416 408 line = '%s%s%s %s' % (Colors.lineno, num,
417 409 Colors.Normal, line)
418 410
419 411 res.append(line)
420 412 if lvals and i == lnum:
421 413 res.append(lvals + '\n')
422 414 i = i + 1
423 415 return res
424 416
425 417 def is_recursion_error(etype, value, records):
426 418 try:
427 419 # RecursionError is new in Python 3.5
428 420 recursion_error_type = RecursionError
429 421 except NameError:
430 422 recursion_error_type = RuntimeError
431 423
432 424 # The default recursion limit is 1000, but some of that will be taken up
433 425 # by stack frames in IPython itself. >500 frames probably indicates
434 426 # a recursion error.
435 427 return (etype is recursion_error_type) \
436 428 and "recursion" in str(value).lower() \
437 429 and len(records) > 500
438 430
439 431 def find_recursion(etype, value, records):
440 432 """Identify the repeating stack frames from a RecursionError traceback
441 433
442 434 'records' is a list as returned by VerboseTB.get_records()
443 435
444 436 Returns (last_unique, repeat_length)
445 437 """
446 438 # This involves a bit of guesswork - we want to show enough of the traceback
447 439 # to indicate where the recursion is occurring. We guess that the innermost
448 440 # quarter of the traceback (250 frames by default) is repeats, and find the
449 441 # first frame (from in to out) that looks different.
450 442 if not is_recursion_error(etype, value, records):
451 443 return len(records), 0
452 444
453 445 # Select filename, lineno, func_name to track frames with
454 446 records = [r[1:4] for r in records]
455 447 inner_frames = records[-(len(records)//4):]
456 448 frames_repeated = set(inner_frames)
457 449
458 450 last_seen_at = {}
459 451 longest_repeat = 0
460 452 i = len(records)
461 453 for frame in reversed(records):
462 454 i -= 1
463 455 if frame not in frames_repeated:
464 456 last_unique = i
465 457 break
466 458
467 459 if frame in last_seen_at:
468 460 distance = last_seen_at[frame] - i
469 461 longest_repeat = max(longest_repeat, distance)
470 462
471 463 last_seen_at[frame] = i
472 464 else:
473 465 last_unique = 0 # The whole traceback was recursion
474 466
475 467 return last_unique, longest_repeat
476 468
477 469 #---------------------------------------------------------------------------
478 470 # Module classes
479 471 class TBTools(object):
480 472 """Basic tools used by all traceback printer classes."""
481 473
482 474 # Number of frames to skip when reporting tracebacks
483 475 tb_offset = 0
484 476
485 477 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
486 478 # Whether to call the interactive pdb debugger after printing
487 479 # tracebacks or not
488 480 self.call_pdb = call_pdb
489 481
490 482 # Output stream to write to. Note that we store the original value in
491 483 # a private attribute and then make the public ostream a property, so
492 484 # that we can delay accessing io.stdout until runtime. The way
493 485 # things are written now, the io.stdout object is dynamically managed
494 486 # so a reference to it should NEVER be stored statically. This
495 487 # property approach confines this detail to a single location, and all
496 488 # subclasses can simply access self.ostream for writing.
497 489 self._ostream = ostream
498 490
499 491 # Create color table
500 492 self.color_scheme_table = exception_colors()
501 493
502 494 self.set_colors(color_scheme)
503 495 self.old_scheme = color_scheme # save initial value for toggles
504 496
505 497 if call_pdb:
506 498 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
507 499 else:
508 500 self.pdb = None
509 501
510 502 def _get_ostream(self):
511 503 """Output stream that exceptions are written to.
512 504
513 505 Valid values are:
514 506
515 507 - None: the default, which means that IPython will dynamically resolve
516 508 to io.stdout. This ensures compatibility with most tools, including
517 509 Windows (where plain stdout doesn't recognize ANSI escapes).
518 510
519 511 - Any object with 'write' and 'flush' attributes.
520 512 """
521 513 return io.stdout if self._ostream is None else self._ostream
522 514
523 515 def _set_ostream(self, val):
524 516 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
525 517 self._ostream = val
526 518
527 519 ostream = property(_get_ostream, _set_ostream)
528 520
529 521 def set_colors(self, *args, **kw):
530 522 """Shorthand access to the color table scheme selector method."""
531 523
532 524 # Set own color table
533 525 self.color_scheme_table.set_active_scheme(*args, **kw)
534 526 # for convenience, set Colors to the active scheme
535 527 self.Colors = self.color_scheme_table.active_colors
536 528 # Also set colors of debugger
537 529 if hasattr(self, 'pdb') and self.pdb is not None:
538 530 self.pdb.set_colors(*args, **kw)
539 531
540 532 def color_toggle(self):
541 533 """Toggle between the currently active color scheme and NoColor."""
542 534
543 535 if self.color_scheme_table.active_scheme_name == 'NoColor':
544 536 self.color_scheme_table.set_active_scheme(self.old_scheme)
545 537 self.Colors = self.color_scheme_table.active_colors
546 538 else:
547 539 self.old_scheme = self.color_scheme_table.active_scheme_name
548 540 self.color_scheme_table.set_active_scheme('NoColor')
549 541 self.Colors = self.color_scheme_table.active_colors
550 542
551 543 def stb2text(self, stb):
552 544 """Convert a structured traceback (a list) to a string."""
553 545 return '\n'.join(stb)
554 546
555 547 def text(self, etype, value, tb, tb_offset=None, context=5):
556 548 """Return formatted traceback.
557 549
558 550 Subclasses may override this if they add extra arguments.
559 551 """
560 552 tb_list = self.structured_traceback(etype, value, tb,
561 553 tb_offset, context)
562 554 return self.stb2text(tb_list)
563 555
564 556 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
565 557 context=5, mode=None):
566 558 """Return a list of traceback frames.
567 559
568 560 Must be implemented by each class.
569 561 """
570 562 raise NotImplementedError()
571 563
572 564
573 565 #---------------------------------------------------------------------------
574 566 class ListTB(TBTools):
575 567 """Print traceback information from a traceback list, with optional color.
576 568
577 569 Calling requires 3 arguments: (etype, evalue, elist)
578 570 as would be obtained by::
579 571
580 572 etype, evalue, tb = sys.exc_info()
581 573 if tb:
582 574 elist = traceback.extract_tb(tb)
583 575 else:
584 576 elist = None
585 577
586 578 It can thus be used by programs which need to process the traceback before
587 579 printing (such as console replacements based on the code module from the
588 580 standard library).
589 581
590 582 Because they are meant to be called without a full traceback (only a
591 583 list), instances of this class can't call the interactive pdb debugger."""
592 584
593 585 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
594 586 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
595 587 ostream=ostream)
596 588
597 589 def __call__(self, etype, value, elist):
598 590 self.ostream.flush()
599 591 self.ostream.write(self.text(etype, value, elist))
600 592 self.ostream.write('\n')
601 593
602 594 def structured_traceback(self, etype, value, elist, tb_offset=None,
603 595 context=5):
604 596 """Return a color formatted string with the traceback info.
605 597
606 598 Parameters
607 599 ----------
608 600 etype : exception type
609 601 Type of the exception raised.
610 602
611 603 value : object
612 604 Data stored in the exception
613 605
614 606 elist : list
615 607 List of frames, see class docstring for details.
616 608
617 609 tb_offset : int, optional
618 610 Number of frames in the traceback to skip. If not given, the
619 611 instance value is used (set in constructor).
620 612
621 613 context : int, optional
622 614 Number of lines of context information to print.
623 615
624 616 Returns
625 617 -------
626 618 String with formatted exception.
627 619 """
628 620 tb_offset = self.tb_offset if tb_offset is None else tb_offset
629 621 Colors = self.Colors
630 622 out_list = []
631 623 if elist:
632 624
633 625 if tb_offset and len(elist) > tb_offset:
634 626 elist = elist[tb_offset:]
635 627
636 628 out_list.append('Traceback %s(most recent call last)%s:' %
637 629 (Colors.normalEm, Colors.Normal) + '\n')
638 630 out_list.extend(self._format_list(elist))
639 631 # The exception info should be a single entry in the list.
640 632 lines = ''.join(self._format_exception_only(etype, value))
641 633 out_list.append(lines)
642 634
643 635 # Note: this code originally read:
644 636
645 637 ## for line in lines[:-1]:
646 638 ## out_list.append(" "+line)
647 639 ## out_list.append(lines[-1])
648 640
649 641 # This means it was indenting everything but the last line by a little
650 642 # bit. I've disabled this for now, but if we see ugliness somewhere we
651 643 # can restore it.
652 644
653 645 return out_list
654 646
655 647 def _format_list(self, extracted_list):
656 648 """Format a list of traceback entry tuples for printing.
657 649
658 650 Given a list of tuples as returned by extract_tb() or
659 651 extract_stack(), return a list of strings ready for printing.
660 652 Each string in the resulting list corresponds to the item with the
661 653 same index in the argument list. Each string ends in a newline;
662 654 the strings may contain internal newlines as well, for those items
663 655 whose source text line is not None.
664 656
665 657 Lifted almost verbatim from traceback.py
666 658 """
667 659
668 660 Colors = self.Colors
669 661 list = []
670 662 for filename, lineno, name, line in extracted_list[:-1]:
671 663 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
672 664 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
673 665 Colors.lineno, lineno, Colors.Normal,
674 666 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
675 667 if line:
676 668 item += ' %s\n' % line.strip()
677 669 list.append(item)
678 670 # Emphasize the last entry
679 671 filename, lineno, name, line = extracted_list[-1]
680 672 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
681 673 (Colors.normalEm,
682 674 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
683 675 Colors.linenoEm, lineno, Colors.normalEm,
684 676 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
685 677 Colors.Normal)
686 678 if line:
687 679 item += '%s %s%s\n' % (Colors.line, line.strip(),
688 680 Colors.Normal)
689 681 list.append(item)
690 682 return list
691 683
692 684 def _format_exception_only(self, etype, value):
693 685 """Format the exception part of a traceback.
694 686
695 687 The arguments are the exception type and value such as given by
696 688 sys.exc_info()[:2]. The return value is a list of strings, each ending
697 689 in a newline. Normally, the list contains a single string; however,
698 690 for SyntaxError exceptions, it contains several lines that (when
699 691 printed) display detailed information about where the syntax error
700 692 occurred. The message indicating which exception occurred is the
701 693 always last string in the list.
702 694
703 695 Also lifted nearly verbatim from traceback.py
704 696 """
705 697 have_filedata = False
706 698 Colors = self.Colors
707 699 list = []
708 700 stype = Colors.excName + etype.__name__ + Colors.Normal
709 701 if value is None:
710 702 # Not sure if this can still happen in Python 2.6 and above
711 703 list.append(py3compat.cast_unicode(stype) + '\n')
712 704 else:
713 705 if issubclass(etype, SyntaxError):
714 706 have_filedata = True
715 707 if not value.filename: value.filename = "<string>"
716 708 if value.lineno:
717 709 lineno = value.lineno
718 710 textline = ulinecache.getline(value.filename, value.lineno)
719 711 else:
720 712 lineno = 'unknown'
721 713 textline = ''
722 714 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
723 715 (Colors.normalEm,
724 716 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
725 717 Colors.linenoEm, lineno, Colors.Normal ))
726 718 if textline == '':
727 719 textline = py3compat.cast_unicode(value.text, "utf-8")
728 720
729 721 if textline is not None:
730 722 i = 0
731 723 while i < len(textline) and textline[i].isspace():
732 724 i += 1
733 725 list.append('%s %s%s\n' % (Colors.line,
734 726 textline.strip(),
735 727 Colors.Normal))
736 728 if value.offset is not None:
737 729 s = ' '
738 730 for c in textline[i:value.offset - 1]:
739 731 if c.isspace():
740 732 s += c
741 733 else:
742 734 s += ' '
743 735 list.append('%s%s^%s\n' % (Colors.caret, s,
744 736 Colors.Normal))
745 737
746 738 try:
747 739 s = value.msg
748 740 except Exception:
749 741 s = self._some_str(value)
750 742 if s:
751 743 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
752 744 Colors.Normal, s))
753 745 else:
754 746 list.append('%s\n' % str(stype))
755 747
756 748 # sync with user hooks
757 749 if have_filedata:
758 750 ipinst = get_ipython()
759 751 if ipinst is not None:
760 752 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
761 753
762 754 return list
763 755
764 756 def get_exception_only(self, etype, value):
765 757 """Only print the exception type and message, without a traceback.
766 758
767 759 Parameters
768 760 ----------
769 761 etype : exception type
770 762 value : exception value
771 763 """
772 764 return ListTB.structured_traceback(self, etype, value, [])
773 765
774 766 def show_exception_only(self, etype, evalue):
775 767 """Only print the exception type and message, without a traceback.
776 768
777 769 Parameters
778 770 ----------
779 771 etype : exception type
780 772 value : exception value
781 773 """
782 774 # This method needs to use __call__ from *this* class, not the one from
783 775 # a subclass whose signature or behavior may be different
784 776 ostream = self.ostream
785 777 ostream.flush()
786 778 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
787 779 ostream.flush()
788 780
789 781 def _some_str(self, value):
790 782 # Lifted from traceback.py
791 783 try:
792 784 return str(value)
793 785 except:
794 786 return '<unprintable %s object>' % type(value).__name__
795 787
796 788
797 789 #----------------------------------------------------------------------------
798 790 class VerboseTB(TBTools):
799 791 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
800 792 of HTML. Requires inspect and pydoc. Crazy, man.
801 793
802 794 Modified version which optionally strips the topmost entries from the
803 795 traceback, to be used with alternate interpreters (because their own code
804 796 would appear in the traceback)."""
805 797
806 798 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
807 799 tb_offset=0, long_header=False, include_vars=True,
808 800 check_cache=None):
809 801 """Specify traceback offset, headers and color scheme.
810 802
811 803 Define how many frames to drop from the tracebacks. Calling it with
812 804 tb_offset=1 allows use of this handler in interpreters which will have
813 805 their own code at the top of the traceback (VerboseTB will first
814 806 remove that frame before printing the traceback info)."""
815 807 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
816 808 ostream=ostream)
817 809 self.tb_offset = tb_offset
818 810 self.long_header = long_header
819 811 self.include_vars = include_vars
820 812 # By default we use linecache.checkcache, but the user can provide a
821 813 # different check_cache implementation. This is used by the IPython
822 814 # kernel to provide tracebacks for interactive code that is cached,
823 815 # by a compiler instance that flushes the linecache but preserves its
824 816 # own code cache.
825 817 if check_cache is None:
826 818 check_cache = linecache.checkcache
827 819 self.check_cache = check_cache
828 820
829 821 def format_records(self, records, last_unique, recursion_repeat):
830 822 """Format the stack frames of the traceback"""
831 823 frames = []
832 824 for r in records[:last_unique+recursion_repeat+1]:
833 825 #print '*** record:',file,lnum,func,lines,index # dbg
834 826 frames.append(self.format_record(*r))
835 827
836 828 if recursion_repeat:
837 829 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
838 830 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
839 831
840 832 return frames
841 833
842 834 def format_record(self, frame, file, lnum, func, lines, index):
843 835 """Format a single stack frame"""
844 836 Colors = self.Colors # just a shorthand + quicker name lookup
845 837 ColorsNormal = Colors.Normal # used a lot
846 838 col_scheme = self.color_scheme_table.active_scheme_name
847 839 indent = ' ' * INDENT_SIZE
848 840 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
849 841 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
850 842 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
851 843 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
852 844 ColorsNormal)
853 845 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
854 846 (Colors.vName, Colors.valEm, ColorsNormal)
855 847 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
856 848 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
857 849 Colors.vName, ColorsNormal)
858 850 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
859 851
860 852 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
861 853 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
862 854 ColorsNormal)
863 855
864 856 abspath = os.path.abspath
865 857
866 858
867 859 if not file:
868 860 file = '?'
869 861 elif file.startswith(str("<")) and file.endswith(str(">")):
870 862 # Not a real filename, no problem...
871 863 pass
872 864 elif not os.path.isabs(file):
873 865 # Try to make the filename absolute by trying all
874 866 # sys.path entries (which is also what linecache does)
875 867 for dirname in sys.path:
876 868 try:
877 869 fullname = os.path.join(dirname, file)
878 870 if os.path.isfile(fullname):
879 871 file = os.path.abspath(fullname)
880 872 break
881 873 except Exception:
882 874 # Just in case that sys.path contains very
883 875 # strange entries...
884 876 pass
885 877
886 878 file = py3compat.cast_unicode(file, util_path.fs_encoding)
887 879 link = tpl_link % file
888 880 args, varargs, varkw, locals = fixed_getargvalues(frame)
889 881
890 882 if func == '?':
891 883 call = ''
892 884 else:
893 885 # Decide whether to include variable details or not
894 886 var_repr = self.include_vars and eqrepr or nullrepr
895 887 try:
896 888 call = tpl_call % (func, inspect.formatargvalues(args,
897 889 varargs, varkw,
898 890 locals, formatvalue=var_repr))
899 891 except KeyError:
900 892 # This happens in situations like errors inside generator
901 893 # expressions, where local variables are listed in the
902 894 # line, but can't be extracted from the frame. I'm not
903 895 # 100% sure this isn't actually a bug in inspect itself,
904 896 # but since there's no info for us to compute with, the
905 897 # best we can do is report the failure and move on. Here
906 898 # we must *not* call any traceback construction again,
907 899 # because that would mess up use of %debug later on. So we
908 900 # simply report the failure and move on. The only
909 901 # limitation will be that this frame won't have locals
910 902 # listed in the call signature. Quite subtle problem...
911 903 # I can't think of a good way to validate this in a unit
912 904 # test, but running a script consisting of:
913 905 # dict( (k,v.strip()) for (k,v) in range(10) )
914 906 # will illustrate the error, if this exception catch is
915 907 # disabled.
916 908 call = tpl_call_fail % func
917 909
918 910 # Don't attempt to tokenize binary files.
919 911 if file.endswith(('.so', '.pyd', '.dll')):
920 912 return '%s %s\n' % (link, call)
921 913
922 914 elif file.endswith(('.pyc', '.pyo')):
923 915 # Look up the corresponding source file.
924 916 file = openpy.source_from_cache(file)
925 917
926 918 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
927 919 line = getline(file, lnum[0])
928 920 lnum[0] += 1
929 921 return line
930 922
931 923 # Build the list of names on this line of code where the exception
932 924 # occurred.
933 925 try:
934 926 names = []
935 927 name_cont = False
936 928
937 929 for token_type, token, start, end, line in generate_tokens(linereader):
938 930 # build composite names
939 931 if token_type == tokenize.NAME and token not in keyword.kwlist:
940 932 if name_cont:
941 933 # Continuation of a dotted name
942 934 try:
943 935 names[-1].append(token)
944 936 except IndexError:
945 937 names.append([token])
946 938 name_cont = False
947 939 else:
948 940 # Regular new names. We append everything, the caller
949 941 # will be responsible for pruning the list later. It's
950 942 # very tricky to try to prune as we go, b/c composite
951 943 # names can fool us. The pruning at the end is easy
952 944 # to do (or the caller can print a list with repeated
953 945 # names if so desired.
954 946 names.append([token])
955 947 elif token == '.':
956 948 name_cont = True
957 949 elif token_type == tokenize.NEWLINE:
958 950 break
959 951
960 952 except (IndexError, UnicodeDecodeError, SyntaxError):
961 953 # signals exit of tokenizer
962 954 # SyntaxError can occur if the file is not actually Python
963 955 # - see gh-6300
964 956 pass
965 957 except tokenize.TokenError as msg:
966 958 _m = ("An unexpected error occurred while tokenizing input\n"
967 959 "The following traceback may be corrupted or invalid\n"
968 960 "The error message is: %s\n" % msg)
969 961 error(_m)
970 962
971 963 # Join composite names (e.g. "dict.fromkeys")
972 964 names = ['.'.join(n) for n in names]
973 965 # prune names list of duplicates, but keep the right order
974 966 unique_names = uniq_stable(names)
975 967
976 968 # Start loop over vars
977 969 lvals = []
978 970 if self.include_vars:
979 971 for name_full in unique_names:
980 972 name_base = name_full.split('.', 1)[0]
981 973 if name_base in frame.f_code.co_varnames:
982 974 if name_base in locals:
983 975 try:
984 976 value = repr(eval(name_full, locals))
985 977 except:
986 978 value = undefined
987 979 else:
988 980 value = undefined
989 981 name = tpl_local_var % name_full
990 982 else:
991 983 if name_base in frame.f_globals:
992 984 try:
993 985 value = repr(eval(name_full, frame.f_globals))
994 986 except:
995 987 value = undefined
996 988 else:
997 989 value = undefined
998 990 name = tpl_global_var % name_full
999 991 lvals.append(tpl_name_val % (name, value))
1000 992 if lvals:
1001 993 lvals = '%s%s' % (indent, em_normal.join(lvals))
1002 994 else:
1003 995 lvals = ''
1004 996
1005 997 level = '%s %s\n' % (link, call)
1006 998
1007 999 if index is None:
1008 1000 return level
1009 1001 else:
1010 1002 return '%s%s' % (level, ''.join(
1011 1003 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1012 1004 col_scheme)))
1013 1005
1014 1006 def prepare_chained_exception_message(self, cause):
1015 1007 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1016 1008 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1017 1009
1018 1010 if cause:
1019 1011 message = [[direct_cause]]
1020 1012 else:
1021 1013 message = [[exception_during_handling]]
1022 1014 return message
1023 1015
1024 1016 def prepare_header(self, etype, long_version=False):
1025 1017 colors = self.Colors # just a shorthand + quicker name lookup
1026 1018 colorsnormal = colors.Normal # used a lot
1027 1019 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1028 1020 if long_version:
1029 1021 # Header with the exception type, python version, and date
1030 1022 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1031 1023 date = time.ctime(time.time())
1032 1024
1033 1025 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
1034 1026 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
1035 1027 pyver, date.rjust(75) )
1036 1028 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1037 1029 "\ncalls leading up to the error, with the most recent (innermost) call last."
1038 1030 else:
1039 1031 # Simplified header
1040 1032 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1041 1033 rjust(75 - len(str(etype))) )
1042 1034
1043 1035 return head
1044 1036
1045 1037 def format_exception(self, etype, evalue):
1046 1038 colors = self.Colors # just a shorthand + quicker name lookup
1047 1039 colorsnormal = colors.Normal # used a lot
1048 1040 indent = ' ' * INDENT_SIZE
1049 1041 # Get (safely) a string form of the exception info
1050 1042 try:
1051 1043 etype_str, evalue_str = map(str, (etype, evalue))
1052 1044 except:
1053 1045 # User exception is improperly defined.
1054 1046 etype, evalue = str, sys.exc_info()[:2]
1055 1047 etype_str, evalue_str = map(str, (etype, evalue))
1056 1048 # ... and format it
1057 1049 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1058 1050 colorsnormal, py3compat.cast_unicode(evalue_str))]
1059 1051
1060 1052 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1061 1053 try:
1062 1054 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1063 1055 except:
1064 1056 # Every now and then, an object with funny internals blows up
1065 1057 # when dir() is called on it. We do the best we can to report
1066 1058 # the problem and continue
1067 1059 _m = '%sException reporting error (object with broken dir())%s:'
1068 1060 exception.append(_m % (colors.excName, colorsnormal))
1069 1061 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1070 1062 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1071 1063 colorsnormal, py3compat.cast_unicode(evalue_str)))
1072 1064 names = []
1073 1065 for name in names:
1074 1066 value = text_repr(getattr(evalue, name))
1075 1067 exception.append('\n%s%s = %s' % (indent, name, value))
1076 1068
1077 1069 return exception
1078 1070
1079 1071 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1080 1072 """Formats the header, traceback and exception message for a single exception.
1081 1073
1082 1074 This may be called multiple times by Python 3 exception chaining
1083 1075 (PEP 3134).
1084 1076 """
1085 1077 # some locals
1086 1078 orig_etype = etype
1087 1079 try:
1088 1080 etype = etype.__name__
1089 1081 except AttributeError:
1090 1082 pass
1091 1083
1092 1084 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1093 1085 head = self.prepare_header(etype, self.long_header)
1094 1086 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1095 1087
1096 1088 if records is None:
1097 1089 return ""
1098 1090
1099 1091 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1100 1092
1101 1093 frames = self.format_records(records, last_unique, recursion_repeat)
1102 1094
1103 1095 formatted_exception = self.format_exception(etype, evalue)
1104 1096 if records:
1105 1097 filepath, lnum = records[-1][1:3]
1106 1098 filepath = os.path.abspath(filepath)
1107 1099 ipinst = get_ipython()
1108 1100 if ipinst is not None:
1109 1101 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1110 1102
1111 1103 return [[head] + frames + [''.join(formatted_exception[0])]]
1112 1104
1113 1105 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1114 1106 try:
1115 1107 # Try the default getinnerframes and Alex's: Alex's fixes some
1116 1108 # problems, but it generates empty tracebacks for console errors
1117 1109 # (5 blanks lines) where none should be returned.
1118 1110 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1119 1111 except:
1120 1112 # FIXME: I've been getting many crash reports from python 2.3
1121 1113 # users, traceable to inspect.py. If I can find a small test-case
1122 1114 # to reproduce this, I should either write a better workaround or
1123 1115 # file a bug report against inspect (if that's the real problem).
1124 1116 # So far, I haven't been able to find an isolated example to
1125 1117 # reproduce the problem.
1126 1118 inspect_error()
1127 1119 traceback.print_exc(file=self.ostream)
1128 1120 info('\nUnfortunately, your original traceback can not be constructed.\n')
1129 1121 return None
1130 1122
1131 1123 def get_parts_of_chained_exception(self, evalue):
1132 1124 def get_chained_exception(exception_value):
1133 1125 cause = getattr(exception_value, '__cause__', None)
1134 1126 if cause:
1135 1127 return cause
1136 1128 if getattr(exception_value, '__suppress_context__', False):
1137 1129 return None
1138 1130 return getattr(exception_value, '__context__', None)
1139 1131
1140 1132 chained_evalue = get_chained_exception(evalue)
1141 1133
1142 1134 if chained_evalue:
1143 1135 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1144 1136
1145 1137 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1146 1138 number_of_lines_of_context=5):
1147 1139 """Return a nice text document describing the traceback."""
1148 1140
1149 1141 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1150 1142 tb_offset)
1151 1143
1152 1144 colors = self.Colors # just a shorthand + quicker name lookup
1153 1145 colorsnormal = colors.Normal # used a lot
1154 1146 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
1155 1147 structured_traceback_parts = [head]
1156 1148 if py3compat.PY3:
1157 1149 chained_exceptions_tb_offset = 0
1158 1150 lines_of_context = 3
1159 1151 formatted_exceptions = formatted_exception
1160 1152 exception = self.get_parts_of_chained_exception(evalue)
1161 1153 if exception:
1162 1154 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1163 1155 etype, evalue, etb = exception
1164 1156 else:
1165 1157 evalue = None
1166 1158 chained_exc_ids = set()
1167 1159 while evalue:
1168 1160 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1169 1161 chained_exceptions_tb_offset)
1170 1162 exception = self.get_parts_of_chained_exception(evalue)
1171 1163
1172 1164 if exception and not id(exception[1]) in chained_exc_ids:
1173 1165 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1174 1166 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1175 1167 etype, evalue, etb = exception
1176 1168 else:
1177 1169 evalue = None
1178 1170
1179 1171 # we want to see exceptions in a reversed order:
1180 1172 # the first exception should be on top
1181 1173 for formatted_exception in reversed(formatted_exceptions):
1182 1174 structured_traceback_parts += formatted_exception
1183 1175 else:
1184 1176 structured_traceback_parts += formatted_exception[0]
1185 1177
1186 1178 return structured_traceback_parts
1187 1179
1188 1180 def debugger(self, force=False):
1189 1181 """Call up the pdb debugger if desired, always clean up the tb
1190 1182 reference.
1191 1183
1192 1184 Keywords:
1193 1185
1194 1186 - force(False): by default, this routine checks the instance call_pdb
1195 1187 flag and does not actually invoke the debugger if the flag is false.
1196 1188 The 'force' option forces the debugger to activate even if the flag
1197 1189 is false.
1198 1190
1199 1191 If the call_pdb flag is set, the pdb interactive debugger is
1200 1192 invoked. In all cases, the self.tb reference to the current traceback
1201 1193 is deleted to prevent lingering references which hamper memory
1202 1194 management.
1203 1195
1204 1196 Note that each call to pdb() does an 'import readline', so if your app
1205 1197 requires a special setup for the readline completers, you'll have to
1206 1198 fix that by hand after invoking the exception handler."""
1207 1199
1208 1200 if force or self.call_pdb:
1209 1201 if self.pdb is None:
1210 1202 self.pdb = debugger.Pdb(
1211 1203 self.color_scheme_table.active_scheme_name)
1212 1204 # the system displayhook may have changed, restore the original
1213 1205 # for pdb
1214 1206 display_trap = DisplayTrap(hook=sys.__displayhook__)
1215 1207 with display_trap:
1216 1208 self.pdb.reset()
1217 1209 # Find the right frame so we don't pop up inside ipython itself
1218 1210 if hasattr(self, 'tb') and self.tb is not None:
1219 1211 etb = self.tb
1220 1212 else:
1221 1213 etb = self.tb = sys.last_traceback
1222 1214 while self.tb is not None and self.tb.tb_next is not None:
1223 1215 self.tb = self.tb.tb_next
1224 1216 if etb and etb.tb_next:
1225 1217 etb = etb.tb_next
1226 1218 self.pdb.botframe = etb.tb_frame
1227 1219 self.pdb.interaction(self.tb.tb_frame, self.tb)
1228 1220
1229 1221 if hasattr(self, 'tb'):
1230 1222 del self.tb
1231 1223
1232 1224 def handler(self, info=None):
1233 1225 (etype, evalue, etb) = info or sys.exc_info()
1234 1226 self.tb = etb
1235 1227 ostream = self.ostream
1236 1228 ostream.flush()
1237 1229 ostream.write(self.text(etype, evalue, etb))
1238 1230 ostream.write('\n')
1239 1231 ostream.flush()
1240 1232
1241 1233 # Changed so an instance can just be called as VerboseTB_inst() and print
1242 1234 # out the right info on its own.
1243 1235 def __call__(self, etype=None, evalue=None, etb=None):
1244 1236 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1245 1237 if etb is None:
1246 1238 self.handler()
1247 1239 else:
1248 1240 self.handler((etype, evalue, etb))
1249 1241 try:
1250 1242 self.debugger()
1251 1243 except KeyboardInterrupt:
1252 1244 print("\nKeyboardInterrupt")
1253 1245
1254 1246
1255 1247 #----------------------------------------------------------------------------
1256 1248 class FormattedTB(VerboseTB, ListTB):
1257 1249 """Subclass ListTB but allow calling with a traceback.
1258 1250
1259 1251 It can thus be used as a sys.excepthook for Python > 2.1.
1260 1252
1261 1253 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1262 1254
1263 1255 Allows a tb_offset to be specified. This is useful for situations where
1264 1256 one needs to remove a number of topmost frames from the traceback (such as
1265 1257 occurs with python programs that themselves execute other python code,
1266 1258 like Python shells). """
1267 1259
1268 1260 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1269 1261 ostream=None,
1270 1262 tb_offset=0, long_header=False, include_vars=False,
1271 1263 check_cache=None):
1272 1264
1273 1265 # NEVER change the order of this list. Put new modes at the end:
1274 1266 self.valid_modes = ['Plain', 'Context', 'Verbose']
1275 1267 self.verbose_modes = self.valid_modes[1:3]
1276 1268
1277 1269 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1278 1270 ostream=ostream, tb_offset=tb_offset,
1279 1271 long_header=long_header, include_vars=include_vars,
1280 1272 check_cache=check_cache)
1281 1273
1282 1274 # Different types of tracebacks are joined with different separators to
1283 1275 # form a single string. They are taken from this dict
1284 1276 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1285 1277 # set_mode also sets the tb_join_char attribute
1286 1278 self.set_mode(mode)
1287 1279
1288 1280 def _extract_tb(self, tb):
1289 1281 if tb:
1290 1282 return traceback.extract_tb(tb)
1291 1283 else:
1292 1284 return None
1293 1285
1294 1286 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1295 1287 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1296 1288 mode = self.mode
1297 1289 if mode in self.verbose_modes:
1298 1290 # Verbose modes need a full traceback
1299 1291 return VerboseTB.structured_traceback(
1300 1292 self, etype, value, tb, tb_offset, number_of_lines_of_context
1301 1293 )
1302 1294 else:
1303 1295 # We must check the source cache because otherwise we can print
1304 1296 # out-of-date source code.
1305 1297 self.check_cache()
1306 1298 # Now we can extract and format the exception
1307 1299 elist = self._extract_tb(tb)
1308 1300 return ListTB.structured_traceback(
1309 1301 self, etype, value, elist, tb_offset, number_of_lines_of_context
1310 1302 )
1311 1303
1312 1304 def stb2text(self, stb):
1313 1305 """Convert a structured traceback (a list) to a string."""
1314 1306 return self.tb_join_char.join(stb)
1315 1307
1316 1308
1317 1309 def set_mode(self, mode=None):
1318 1310 """Switch to the desired mode.
1319 1311
1320 1312 If mode is not specified, cycles through the available modes."""
1321 1313
1322 1314 if not mode:
1323 1315 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1324 1316 len(self.valid_modes)
1325 1317 self.mode = self.valid_modes[new_idx]
1326 1318 elif mode not in self.valid_modes:
1327 1319 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1328 1320 'Valid modes: ' + str(self.valid_modes))
1329 1321 else:
1330 1322 self.mode = mode
1331 1323 # include variable details only in 'Verbose' mode
1332 1324 self.include_vars = (self.mode == self.valid_modes[2])
1333 1325 # Set the join character for generating text tracebacks
1334 1326 self.tb_join_char = self._join_chars[self.mode]
1335 1327
1336 1328 # some convenient shortcuts
1337 1329 def plain(self):
1338 1330 self.set_mode(self.valid_modes[0])
1339 1331
1340 1332 def context(self):
1341 1333 self.set_mode(self.valid_modes[1])
1342 1334
1343 1335 def verbose(self):
1344 1336 self.set_mode(self.valid_modes[2])
1345 1337
1346 1338
1347 1339 #----------------------------------------------------------------------------
1348 1340 class AutoFormattedTB(FormattedTB):
1349 1341 """A traceback printer which can be called on the fly.
1350 1342
1351 1343 It will find out about exceptions by itself.
1352 1344
1353 1345 A brief example::
1354 1346
1355 1347 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1356 1348 try:
1357 1349 ...
1358 1350 except:
1359 1351 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1360 1352 """
1361 1353
1362 1354 def __call__(self, etype=None, evalue=None, etb=None,
1363 1355 out=None, tb_offset=None):
1364 1356 """Print out a formatted exception traceback.
1365 1357
1366 1358 Optional arguments:
1367 1359 - out: an open file-like object to direct output to.
1368 1360
1369 1361 - tb_offset: the number of frames to skip over in the stack, on a
1370 1362 per-call basis (this overrides temporarily the instance's tb_offset
1371 1363 given at initialization time. """
1372 1364
1373 1365 if out is None:
1374 1366 out = self.ostream
1375 1367 out.flush()
1376 1368 out.write(self.text(etype, evalue, etb, tb_offset))
1377 1369 out.write('\n')
1378 1370 out.flush()
1379 1371 # FIXME: we should remove the auto pdb behavior from here and leave
1380 1372 # that to the clients.
1381 1373 try:
1382 1374 self.debugger()
1383 1375 except KeyboardInterrupt:
1384 1376 print("\nKeyboardInterrupt")
1385 1377
1386 1378 def structured_traceback(self, etype=None, value=None, tb=None,
1387 1379 tb_offset=None, number_of_lines_of_context=5):
1388 1380 if etype is None:
1389 1381 etype, value, tb = sys.exc_info()
1390 1382 self.tb = tb
1391 1383 return FormattedTB.structured_traceback(
1392 1384 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1393 1385
1394 1386
1395 1387 #---------------------------------------------------------------------------
1396 1388
1397 1389 # A simple class to preserve Nathan's original functionality.
1398 1390 class ColorTB(FormattedTB):
1399 1391 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1400 1392
1401 1393 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1402 1394 FormattedTB.__init__(self, color_scheme=color_scheme,
1403 1395 call_pdb=call_pdb, **kwargs)
1404 1396
1405 1397
1406 1398 class SyntaxTB(ListTB):
1407 1399 """Extension which holds some state: the last exception value"""
1408 1400
1409 1401 def __init__(self, color_scheme='NoColor'):
1410 1402 ListTB.__init__(self, color_scheme)
1411 1403 self.last_syntax_error = None
1412 1404
1413 1405 def __call__(self, etype, value, elist):
1414 1406 self.last_syntax_error = value
1415 1407
1416 1408 ListTB.__call__(self, etype, value, elist)
1417 1409
1418 1410 def structured_traceback(self, etype, value, elist, tb_offset=None,
1419 1411 context=5):
1420 1412 # If the source file has been edited, the line in the syntax error can
1421 1413 # be wrong (retrieved from an outdated cache). This replaces it with
1422 1414 # the current value.
1423 1415 if isinstance(value, SyntaxError) \
1424 1416 and isinstance(value.filename, py3compat.string_types) \
1425 1417 and isinstance(value.lineno, int):
1426 1418 linecache.checkcache(value.filename)
1427 1419 newtext = ulinecache.getline(value.filename, value.lineno)
1428 1420 if newtext:
1429 1421 value.text = newtext
1430 1422 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1431 1423 tb_offset=tb_offset, context=context)
1432 1424
1433 1425 def clear_err_state(self):
1434 1426 """Return the current error state and clear it"""
1435 1427 e = self.last_syntax_error
1436 1428 self.last_syntax_error = None
1437 1429 return e
1438 1430
1439 1431 def stb2text(self, stb):
1440 1432 """Convert a structured traceback (a list) to a string."""
1441 1433 return ''.join(stb)
1442 1434
1443 1435
1444 1436 # some internal-use functions
1445 1437 def text_repr(value):
1446 1438 """Hopefully pretty robust repr equivalent."""
1447 1439 # this is pretty horrible but should always return *something*
1448 1440 try:
1449 1441 return pydoc.text.repr(value)
1450 1442 except KeyboardInterrupt:
1451 1443 raise
1452 1444 except:
1453 1445 try:
1454 1446 return repr(value)
1455 1447 except KeyboardInterrupt:
1456 1448 raise
1457 1449 except:
1458 1450 try:
1459 1451 # all still in an except block so we catch
1460 1452 # getattr raising
1461 1453 name = getattr(value, '__name__', None)
1462 1454 if name:
1463 1455 # ick, recursion
1464 1456 return text_repr(name)
1465 1457 klass = getattr(value, '__class__', None)
1466 1458 if klass:
1467 1459 return '%s instance' % text_repr(klass)
1468 1460 except KeyboardInterrupt:
1469 1461 raise
1470 1462 except:
1471 1463 return 'UNRECOVERABLE REPR FAILURE'
1472 1464
1473 1465
1474 1466 def eqrepr(value, repr=text_repr):
1475 1467 return '=%s' % repr(value)
1476 1468
1477 1469
1478 1470 def nullrepr(value, repr=text_repr):
1479 1471 return ''
General Comments 0
You need to be logged in to leave comments. Login now