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