##// END OF EJS Templates
Reuse CLI in between pdb prompts...
Matthias Bussonnier -
Show More
@@ -1,642 +1,661 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, py3compat
37 37 from IPython.core.completer import IPCompleter
38 38 from IPython.core.excolors import exception_colors
39 39 from IPython.testing.skipdoctest import skip_doctest
40 40 from IPython.terminal.ptutils import IPythonPTCompleter
41 41
42 from prompt_toolkit import prompt as ptk_prompt
43 42 from prompt_toolkit.token import Token
43 from prompt_toolkit.shortcuts import create_prompt_application
44 from prompt_toolkit.interface import CommandLineInterface
45 from prompt_toolkit.enums import EditingMode
46
44 47
45 48 prompt = 'ipdb> '
46 49
47 50 #We have to check this directly from sys.argv, config struct not yet available
48 51 from pdb import Pdb as OldPdb
49 52
50 53 # Allow the set_trace code to operate outside of an ipython instance, even if
51 54 # it does so with some limitations. The rest of this support is implemented in
52 55 # the Tracer constructor.
53 56
54 57 def make_arrow(pad):
55 58 """generate the leading arrow in front of traceback or debugger"""
56 59 if pad >= 2:
57 60 return '-'*(pad-2) + '> '
58 61 elif pad == 1:
59 62 return '>'
60 63 return ''
61 64
62 65
63 66 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
64 67 """Exception hook which handles `BdbQuit` exceptions.
65 68
66 69 All other exceptions are processed using the `excepthook`
67 70 parameter.
68 71 """
69 72 if et==bdb.BdbQuit:
70 73 print('Exiting Debugger.')
71 74 elif excepthook is not None:
72 75 excepthook(et, ev, tb)
73 76 else:
74 77 # Backwards compatibility. Raise deprecation warning?
75 78 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
76 79
77 80 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
78 81 print('Exiting Debugger.')
79 82
80 83
81 84 class Tracer(object):
82 85 """Class for local debugging, similar to pdb.set_trace.
83 86
84 87 Instances of this class, when called, behave like pdb.set_trace, but
85 88 providing IPython's enhanced capabilities.
86 89
87 90 This is implemented as a class which must be initialized in your own code
88 91 and not as a standalone function because we need to detect at runtime
89 92 whether IPython is already active or not. That detection is done in the
90 93 constructor, ensuring that this code plays nicely with a running IPython,
91 94 while functioning acceptably (though with limitations) if outside of it.
92 95 """
93 96
94 97 @skip_doctest
95 98 def __init__(self, colors=None):
96 99 """Create a local debugger instance.
97 100
98 101 Parameters
99 102 ----------
100 103
101 104 colors : str, optional
102 105 The name of the color scheme to use, it must be one of IPython's
103 106 valid color schemes. If not given, the function will default to
104 107 the current IPython scheme when running inside IPython, and to
105 108 'NoColor' otherwise.
106 109
107 110 Examples
108 111 --------
109 112 ::
110 113
111 114 from IPython.core.debugger import Tracer; debug_here = Tracer()
112 115
113 116 Later in your code::
114 117
115 118 debug_here() # -> will open up the debugger at that point.
116 119
117 120 Once the debugger activates, you can use all of its regular commands to
118 121 step through code, set breakpoints, etc. See the pdb documentation
119 122 from the Python standard library for usage details.
120 123 """
121 124
122 125 ip = get_ipython()
123 126 if ip is None:
124 127 # Outside of ipython, we set our own exception hook manually
125 128 sys.excepthook = functools.partial(BdbQuit_excepthook,
126 129 excepthook=sys.excepthook)
127 130 def_colors = 'NoColor'
128 131 else:
129 132 # In ipython, we use its custom exception handler mechanism
130 133 def_colors = ip.colors
131 134 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
132 135
133 136 if colors is None:
134 137 colors = def_colors
135 138
136 139 # The stdlib debugger internally uses a modified repr from the `repr`
137 140 # module, that limits the length of printed strings to a hardcoded
138 141 # limit of 30 characters. That much trimming is too aggressive, let's
139 142 # at least raise that limit to 80 chars, which should be enough for
140 143 # most interactive uses.
141 144 try:
142 145 try:
143 146 from reprlib import aRepr # Py 3
144 147 except ImportError:
145 148 from repr import aRepr # Py 2
146 149 aRepr.maxstring = 80
147 150 except:
148 151 # This is only a user-facing convenience, so any error we encounter
149 152 # here can be warned about but can be otherwise ignored. These
150 153 # printouts will tell us about problems if this API changes
151 154 import traceback
152 155 traceback.print_exc()
153 156
154 157 self.debugger = Pdb(colors)
155 158
156 159 def __call__(self):
157 160 """Starts an interactive debugger at the point where called.
158 161
159 162 This is similar to the pdb.set_trace() function from the std lib, but
160 163 using IPython's enhanced debugger."""
161 164
162 165 self.debugger.set_trace(sys._getframe().f_back)
163 166
164 167
165 168 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
166 169 """Make new_fn have old_fn's doc string. This is particularly useful
167 170 for the ``do_...`` commands that hook into the help system.
168 171 Adapted from from a comp.lang.python posting
169 172 by Duncan Booth."""
170 173 def wrapper(*args, **kw):
171 174 return new_fn(*args, **kw)
172 175 if old_fn.__doc__:
173 176 wrapper.__doc__ = old_fn.__doc__ + additional_text
174 177 return wrapper
175 178
176 179
177 180 def _file_lines(fname):
178 181 """Return the contents of a named file as a list of lines.
179 182
180 183 This function never raises an IOError exception: if the file can't be
181 184 read, it simply returns an empty list."""
182 185
183 186 try:
184 187 outfile = open(fname)
185 188 except IOError:
186 189 return []
187 190 else:
188 191 out = outfile.readlines()
189 192 outfile.close()
190 193 return out
191 194
192 195
193 196 class Pdb(OldPdb, object):
194 197 """Modified Pdb class, does not load readline."""
195 198
196 199 def __init__(self,color_scheme='NoColor',completekey=None,
197 200 stdin=None, stdout=None, context=5):
198 201
199 202 # Parent constructor:
200 203 try:
201 204 self.context=int(context)
202 205 if self.context <= 0:
203 206 raise ValueError("Context must be a positive integer")
204 207 except (TypeError, ValueError):
205 208 raise ValueError("Context must be a positive integer")
206 209
207 210 OldPdb.__init__(self,completekey,stdin,stdout)
208 211
209 212 # IPython changes...
210 213 self.shell = get_ipython()
211 214
212 215 if self.shell is None:
213 216 # No IPython instance running, we must create one
214 217 from IPython.terminal.interactiveshell import \
215 218 TerminalInteractiveShell
216 219 self.shell = TerminalInteractiveShell.instance()
217 220
218 221 # This is icky, but I'm not currently sure how best to test if we're
219 222 # in a terminal shell using prompt_toolkit
220 self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli')
221 223
222 224 self.aliases = {}
223 225
224 226 # Create color table: we copy the default one from the traceback
225 227 # module and add a few attributes needed for debugging
226 228 self.color_scheme_table = exception_colors()
227 229
228 230 # shorthands
229 231 C = coloransi.TermColors
230 232 cst = self.color_scheme_table
231 233
232 234 cst['NoColor'].colors.prompt = C.NoColor
233 235 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
234 236 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
235 237
236 238 cst['Linux'].colors.prompt = C.Green
237 239 cst['Linux'].colors.breakpoint_enabled = C.LightRed
238 240 cst['Linux'].colors.breakpoint_disabled = C.Red
239 241
240 242 cst['LightBG'].colors.prompt = C.Blue
241 243 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
242 244 cst['LightBG'].colors.breakpoint_disabled = C.Red
243 245
244 246 self.set_colors(color_scheme)
245 247
246 248 # Add a python parser so we can syntax highlight source while
247 249 # debugging.
248 250 self.parser = PyColorize.Parser()
249 251
250 252 # Set the prompt - the default prompt is '(Pdb)'
251 253 self.prompt = prompt
252 254 self._ptcomp = None
255 self.pt_init()
256
257 def pt_init(self):
258 self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli')
259
260 if not self.use_prompt_toolkit:
261 return
262
263 def get_prompt_tokens(cli):
264 return [(Token.Prompt, self.prompt)]
265
266 if self._ptcomp is None:
267 compl = IPCompleter(shell=self.shell,
268 namespace={},
269 global_namespace={},
270 use_readline=False,
271 parent=self.shell,
272 )
273 self._ptcomp = IPythonPTCompleter(compl)
274
275 self._pt_app = create_prompt_application(
276 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
277 history=self.shell.debugger_history,
278 completer= self._ptcomp,
279 enable_history_search=True,
280 mouse_support=self.shell.mouse_support,
281 get_prompt_tokens=get_prompt_tokens
282 )
283 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
284
253 285
254 286
255 287 def cmdloop(self, intro=None):
256 288 """Repeatedly issue a prompt, accept input, parse an initial prefix
257 289 off the received input, and dispatch to action methods, passing them
258 290 the remainder of the line as argument.
259 291
260 292 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
261 293 """
262 294 if not self.use_prompt_toolkit:
263 295 return OldPdb.cmdloop(self, intro)
264 296
265 297 if not self.use_rawinput:
266 298 raise ValueError('Sorry ipdb does not support raw_input=False')
267 299
268 def get_prompt_tokens(cli):
269 return [(Token.Prompt, self.prompt)]
270 300
271 301 self.preloop()
272 302
273 if self._ptcomp is None:
274 compl = IPCompleter(shell=self.shell,
275 namespace=self.curframe_locals,
276 global_namespace=self.curframe.f_globals,
277 use_readline=False,
278 parent=self.shell,
279 )
280 self._ptcomp = IPythonPTCompleter(compl)
281 303
282 304 try:
283 305 if intro is not None:
284 306 self.intro = intro
285 307 if self.intro:
286 308 self.stdout.write(str(self.intro)+"\n")
287 309 stop = None
288 310 while not stop:
289 311 if self.cmdqueue:
290 312 line = self.cmdqueue.pop(0)
291 313 else:
292 314 self._ptcomp.ipy_completer.namespace = self.curframe_locals
293 315 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
294 316 try:
295 line = ptk_prompt(get_prompt_tokens=get_prompt_tokens,
296 history=self.shell.debugger_history,
297 completer=self._ptcomp
298 )
317 line = self.pt_cli.run(reset_current_buffer=True).text
299 318 except EOFError:
300 319 line = 'EOF'
301 320 line = self.precmd(line)
302 321 stop = self.onecmd(line)
303 322 stop = self.postcmd(stop, line)
304 323 self.postloop()
305 324 except Exception:
306 pass
325 raise
307 326
308 327
309 328
310 329 def set_colors(self, scheme):
311 330 """Shorthand access to the color table scheme selector method."""
312 331 self.color_scheme_table.set_active_scheme(scheme)
313 332
314 333 def interaction(self, frame, traceback):
315 334 try:
316 335 OldPdb.interaction(self, frame, traceback)
317 336 except KeyboardInterrupt:
318 337 sys.stdout.write('\n' + self.shell.get_exception_only())
319 338
320 339 def parseline(self, line):
321 340 if line.startswith("!!"):
322 341 # Force standard behavior.
323 342 return super(Pdb, self).parseline(line[2:])
324 343 # "Smart command mode" from pdb++: don't execute commands if a variable
325 344 # with the same name exists.
326 345 cmd, arg, newline = super(Pdb, self).parseline(line)
327 346 if cmd in self.curframe.f_globals or cmd in self.curframe.f_locals:
328 347 return super(Pdb, self).parseline("!" + line)
329 348 return super(Pdb, self).parseline(line)
330 349
331 350 def new_do_up(self, arg):
332 351 OldPdb.do_up(self, arg)
333 352 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
334 353
335 354 def new_do_down(self, arg):
336 355 OldPdb.do_down(self, arg)
337 356
338 357 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
339 358
340 359 def new_do_frame(self, arg):
341 360 OldPdb.do_frame(self, arg)
342 361
343 362 def new_do_quit(self, arg):
344 363
345 364 if hasattr(self, 'old_all_completions'):
346 365 self.shell.Completer.all_completions=self.old_all_completions
347 366
348 367 return OldPdb.do_quit(self, arg)
349 368
350 369 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
351 370
352 371 def new_do_restart(self, arg):
353 372 """Restart command. In the context of ipython this is exactly the same
354 373 thing as 'quit'."""
355 374 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
356 375 return self.do_quit(arg)
357 376
358 377 def print_stack_trace(self, context=None):
359 378 if context is None:
360 379 context = self.context
361 380 try:
362 381 context=int(context)
363 382 if context <= 0:
364 383 raise ValueError("Context must be a positive integer")
365 384 except (TypeError, ValueError):
366 385 raise ValueError("Context must be a positive integer")
367 386 try:
368 387 for frame_lineno in self.stack:
369 388 self.print_stack_entry(frame_lineno, context=context)
370 389 except KeyboardInterrupt:
371 390 pass
372 391
373 392 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
374 393 context=None):
375 394 if context is None:
376 395 context = self.context
377 396 try:
378 397 context=int(context)
379 398 if context <= 0:
380 399 raise ValueError("Context must be a positive integer")
381 400 except (TypeError, ValueError):
382 401 raise ValueError("Context must be a positive integer")
383 402 print(self.format_stack_entry(frame_lineno, '', context))
384 403
385 404 # vds: >>
386 405 frame, lineno = frame_lineno
387 406 filename = frame.f_code.co_filename
388 407 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
389 408 # vds: <<
390 409
391 410 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
392 411 if context is None:
393 412 context = self.context
394 413 try:
395 414 context=int(context)
396 415 if context <= 0:
397 416 print("Context must be a positive integer")
398 417 except (TypeError, ValueError):
399 418 print("Context must be a positive integer")
400 419 try:
401 420 import reprlib # Py 3
402 421 except ImportError:
403 422 import repr as reprlib # Py 2
404 423
405 424 ret = []
406 425
407 426 Colors = self.color_scheme_table.active_colors
408 427 ColorsNormal = Colors.Normal
409 428 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
410 429 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
411 430 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
412 431 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
413 432 ColorsNormal)
414 433
415 434 frame, lineno = frame_lineno
416 435
417 436 return_value = ''
418 437 if '__return__' in frame.f_locals:
419 438 rv = frame.f_locals['__return__']
420 439 #return_value += '->'
421 440 return_value += reprlib.repr(rv) + '\n'
422 441 ret.append(return_value)
423 442
424 443 #s = filename + '(' + `lineno` + ')'
425 444 filename = self.canonic(frame.f_code.co_filename)
426 445 link = tpl_link % py3compat.cast_unicode(filename)
427 446
428 447 if frame.f_code.co_name:
429 448 func = frame.f_code.co_name
430 449 else:
431 450 func = "<lambda>"
432 451
433 452 call = ''
434 453 if func != '?':
435 454 if '__args__' in frame.f_locals:
436 455 args = reprlib.repr(frame.f_locals['__args__'])
437 456 else:
438 457 args = '()'
439 458 call = tpl_call % (func, args)
440 459
441 460 # The level info should be generated in the same format pdb uses, to
442 461 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
443 462 if frame is self.curframe:
444 463 ret.append('> ')
445 464 else:
446 465 ret.append(' ')
447 466 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
448 467
449 468 start = lineno - 1 - context//2
450 469 lines = ulinecache.getlines(filename)
451 470 start = min(start, len(lines) - context)
452 471 start = max(start, 0)
453 472 lines = lines[start : start + context]
454 473
455 474 for i,line in enumerate(lines):
456 475 show_arrow = (start + 1 + i == lineno)
457 476 linetpl = (frame is self.curframe or show_arrow) \
458 477 and tpl_line_em \
459 478 or tpl_line
460 479 ret.append(self.__format_line(linetpl, filename,
461 480 start + 1 + i, line,
462 481 arrow = show_arrow) )
463 482 return ''.join(ret)
464 483
465 484 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
466 485 bp_mark = ""
467 486 bp_mark_color = ""
468 487
469 488 scheme = self.color_scheme_table.active_scheme_name
470 489 new_line, err = self.parser.format2(line, 'str', scheme)
471 490 if not err: line = new_line
472 491
473 492 bp = None
474 493 if lineno in self.get_file_breaks(filename):
475 494 bps = self.get_breaks(filename, lineno)
476 495 bp = bps[-1]
477 496
478 497 if bp:
479 498 Colors = self.color_scheme_table.active_colors
480 499 bp_mark = str(bp.number)
481 500 bp_mark_color = Colors.breakpoint_enabled
482 501 if not bp.enabled:
483 502 bp_mark_color = Colors.breakpoint_disabled
484 503
485 504 numbers_width = 7
486 505 if arrow:
487 506 # This is the line with the error
488 507 pad = numbers_width - len(str(lineno)) - len(bp_mark)
489 508 num = '%s%s' % (make_arrow(pad), str(lineno))
490 509 else:
491 510 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
492 511
493 512 return tpl_line % (bp_mark_color + bp_mark, num, line)
494 513
495 514
496 515 def print_list_lines(self, filename, first, last):
497 516 """The printing (as opposed to the parsing part of a 'list'
498 517 command."""
499 518 try:
500 519 Colors = self.color_scheme_table.active_colors
501 520 ColorsNormal = Colors.Normal
502 521 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
503 522 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
504 523 src = []
505 524 if filename == "<string>" and hasattr(self, "_exec_filename"):
506 525 filename = self._exec_filename
507 526
508 527 for lineno in range(first, last+1):
509 528 line = ulinecache.getline(filename, lineno)
510 529 if not line:
511 530 break
512 531
513 532 if lineno == self.curframe.f_lineno:
514 533 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
515 534 else:
516 535 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
517 536
518 537 src.append(line)
519 538 self.lineno = lineno
520 539
521 540 print(''.join(src))
522 541
523 542 except KeyboardInterrupt:
524 543 pass
525 544
526 545 def do_list(self, arg):
527 546 self.lastcmd = 'list'
528 547 last = None
529 548 if arg:
530 549 try:
531 550 x = eval(arg, {}, {})
532 551 if type(x) == type(()):
533 552 first, last = x
534 553 first = int(first)
535 554 last = int(last)
536 555 if last < first:
537 556 # Assume it's a count
538 557 last = first + last
539 558 else:
540 559 first = max(1, int(x) - 5)
541 560 except:
542 561 print('*** Error in argument:', repr(arg))
543 562 return
544 563 elif self.lineno is None:
545 564 first = max(1, self.curframe.f_lineno - 5)
546 565 else:
547 566 first = self.lineno + 1
548 567 if last is None:
549 568 last = first + 10
550 569 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
551 570
552 571 # vds: >>
553 572 lineno = first
554 573 filename = self.curframe.f_code.co_filename
555 574 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
556 575 # vds: <<
557 576
558 577 do_l = do_list
559 578
560 579 def getsourcelines(self, obj):
561 580 lines, lineno = inspect.findsource(obj)
562 581 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
563 582 # must be a module frame: do not try to cut a block out of it
564 583 return lines, 1
565 584 elif inspect.ismodule(obj):
566 585 return lines, 1
567 586 return inspect.getblock(lines[lineno:]), lineno+1
568 587
569 588 def do_longlist(self, arg):
570 589 self.lastcmd = 'longlist'
571 590 try:
572 591 lines, lineno = self.getsourcelines(self.curframe)
573 592 except OSError as err:
574 593 self.error(err)
575 594 return
576 595 last = lineno + len(lines)
577 596 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
578 597 do_ll = do_longlist
579 598
580 599 def do_pdef(self, arg):
581 600 """Print the call signature for any callable object.
582 601
583 602 The debugger interface to %pdef"""
584 603 namespaces = [('Locals', self.curframe.f_locals),
585 604 ('Globals', self.curframe.f_globals)]
586 605 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
587 606
588 607 def do_pdoc(self, arg):
589 608 """Print the docstring for an object.
590 609
591 610 The debugger interface to %pdoc."""
592 611 namespaces = [('Locals', self.curframe.f_locals),
593 612 ('Globals', self.curframe.f_globals)]
594 613 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
595 614
596 615 def do_pfile(self, arg):
597 616 """Print (or run through pager) the file where an object is defined.
598 617
599 618 The debugger interface to %pfile.
600 619 """
601 620 namespaces = [('Locals', self.curframe.f_locals),
602 621 ('Globals', self.curframe.f_globals)]
603 622 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
604 623
605 624 def do_pinfo(self, arg):
606 625 """Provide detailed information about an object.
607 626
608 627 The debugger interface to %pinfo, i.e., obj?."""
609 628 namespaces = [('Locals', self.curframe.f_locals),
610 629 ('Globals', self.curframe.f_globals)]
611 630 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
612 631
613 632 def do_pinfo2(self, arg):
614 633 """Provide extra detailed information about an object.
615 634
616 635 The debugger interface to %pinfo2, i.e., obj??."""
617 636 namespaces = [('Locals', self.curframe.f_locals),
618 637 ('Globals', self.curframe.f_globals)]
619 638 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
620 639
621 640 def do_psource(self, arg):
622 641 """Print (or run through pager) the source code for an object."""
623 642 namespaces = [('Locals', self.curframe.f_locals),
624 643 ('Globals', self.curframe.f_globals)]
625 644 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
626 645
627 646 if sys.version_info > (3, ):
628 647 def do_where(self, arg):
629 648 """w(here)
630 649 Print a stack trace, with the most recent frame at the bottom.
631 650 An arrow indicates the "current frame", which determines the
632 651 context of most commands. 'bt' is an alias for this command.
633 652
634 653 Take a number as argument as an (optional) number of context line to
635 654 print"""
636 655 if arg:
637 656 context = int(arg)
638 657 self.print_stack_trace(context)
639 658 else:
640 659 self.print_stack_trace()
641 660
642 661 do_w = do_where
General Comments 0
You need to be logged in to leave comments. Login now