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