Add "longlist" and "source" commands, ideas borrowed from pdb++ by Antonio Cuni.
This commit is contained in:
parent
0d08962659
commit
e59ca2afe3
|
@ -368,6 +368,12 @@ by the local file.
|
|||
list 11 lines around at that line. With two arguments, list the given range;
|
||||
if the second argument is less than the first, it is interpreted as a count.
|
||||
|
||||
.. pdbcommand:: ll | longlist
|
||||
|
||||
List all source code for the current function or frame.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
.. pdbcommand:: a(rgs)
|
||||
|
||||
Print the argument list of the current function.
|
||||
|
@ -385,6 +391,12 @@ by the local file.
|
|||
|
||||
Print the type of the *expression*.
|
||||
|
||||
.. pdbcommand:: source expression
|
||||
|
||||
Try to get source code for the given object and display it.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
.. _debugger-aliases:
|
||||
|
||||
.. pdbcommand:: alias [name [command]]
|
||||
|
|
75
Lib/pdb.py
75
Lib/pdb.py
|
@ -74,6 +74,8 @@ import os
|
|||
import re
|
||||
import pprint
|
||||
import traceback
|
||||
import inspect
|
||||
import types
|
||||
|
||||
|
||||
class Restart(Exception):
|
||||
|
@ -1028,25 +1030,62 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
|||
filename = self.curframe.f_code.co_filename
|
||||
breaklist = self.get_file_breaks(filename)
|
||||
try:
|
||||
for lineno in range(first, last+1):
|
||||
line = linecache.getline(filename, lineno,
|
||||
self.curframe.f_globals)
|
||||
if not line:
|
||||
self.message('[EOF]')
|
||||
break
|
||||
else:
|
||||
s = repr(lineno).rjust(3)
|
||||
if len(s) < 4: s = s + ' '
|
||||
if lineno in breaklist: s = s + 'B'
|
||||
else: s = s + ' '
|
||||
if lineno == self.curframe.f_lineno:
|
||||
s = s + '->'
|
||||
self.message(s + '\t' + line.rstrip())
|
||||
self.lineno = lineno
|
||||
# XXX add tb_lineno feature
|
||||
lines = linecache.getlines(filename, self.curframe.f_globals)
|
||||
self._print_lines(lines[first-1:last], first, breaklist,
|
||||
self.curframe.f_lineno, -1)
|
||||
self.lineno = min(last, len(lines))
|
||||
if len(lines) < last:
|
||||
self.message('[EOF]')
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
do_l = do_list
|
||||
|
||||
def do_longlist(self, arg):
|
||||
"""longlist | ll
|
||||
List the whole source code for the current function or frame.
|
||||
"""
|
||||
filename = self.curframe.f_code.co_filename
|
||||
breaklist = self.get_file_breaks(filename)
|
||||
try:
|
||||
lines, lineno = inspect.getsourcelines(self.curframe)
|
||||
except IOError as err:
|
||||
self.error(err)
|
||||
return
|
||||
self._print_lines(lines, lineno, breaklist, self.curframe.f_lineno, -1)
|
||||
do_ll = do_longlist
|
||||
|
||||
def do_source(self, arg):
|
||||
"""source expression
|
||||
Try to get source code for the given object and display it.
|
||||
"""
|
||||
try:
|
||||
obj = self._getval(arg)
|
||||
except:
|
||||
return
|
||||
try:
|
||||
lines, lineno = inspect.getsourcelines(obj)
|
||||
except (IOError, TypeError) as err:
|
||||
self.error(err)
|
||||
return
|
||||
self._print_lines(lines, lineno, [], -1, -1)
|
||||
|
||||
def _print_lines(self, lines, start, breaks, current, special):
|
||||
"""Print a range of lines."""
|
||||
for lineno, line in enumerate(lines, start):
|
||||
s = str(lineno).rjust(3)
|
||||
if len(s) < 4:
|
||||
s += ' '
|
||||
if lineno in breaks:
|
||||
s += 'B'
|
||||
else:
|
||||
s += ' '
|
||||
if lineno == current:
|
||||
s += '->'
|
||||
elif lineno == special:
|
||||
s += '>>'
|
||||
self.message(s + '\t' + line.rstrip())
|
||||
|
||||
def do_whatis(self, arg):
|
||||
"""whatis arg
|
||||
Print the type of the argument.
|
||||
|
@ -1249,10 +1288,12 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
|||
_help_order = [
|
||||
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
|
||||
'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
|
||||
'jump', 'return', 'retval', 'run', 'continue', 'list', 'args', 'print',
|
||||
'whatis', 'alias', 'unalias', 'quit',
|
||||
'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
|
||||
'args', 'print', 'pp', 'whatis', 'source', 'alias', 'unalias',
|
||||
'debug', 'quit',
|
||||
]
|
||||
|
||||
docs = set()
|
||||
for _command in _help_order:
|
||||
__doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
|
||||
__doc__ += Pdb.help_exec.__doc__
|
||||
|
|
|
@ -257,6 +257,105 @@ def test_pdb_breakpoint_commands():
|
|||
"""
|
||||
|
||||
|
||||
def do_nothing():
|
||||
pass
|
||||
|
||||
def do_something():
|
||||
print(42)
|
||||
|
||||
def test_list_commands():
|
||||
"""Test the list and source commands of pdb.
|
||||
|
||||
>>> def test_function_2(foo):
|
||||
... import test_pdb
|
||||
... test_pdb.do_nothing()
|
||||
... 'some...'
|
||||
... 'more...'
|
||||
... 'code...'
|
||||
... 'to...'
|
||||
... 'make...'
|
||||
... 'a...'
|
||||
... 'long...'
|
||||
... 'listing...'
|
||||
... 'useful...'
|
||||
... '...'
|
||||
... '...'
|
||||
... return foo
|
||||
|
||||
>>> def test_function():
|
||||
... import pdb; pdb.Pdb().set_trace()
|
||||
... ret = test_function_2('baz')
|
||||
|
||||
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
|
||||
... 'list', # list first function
|
||||
... 'step', # step into second function
|
||||
... 'list', # list second function
|
||||
... 'list', # continue listing to EOF
|
||||
... 'list 1,3', # list specific lines
|
||||
... 'list x', # invalid argument
|
||||
... 'next', # step to import
|
||||
... 'next', # step over import
|
||||
... 'step', # step into do_nothing
|
||||
... 'longlist', # list all lines
|
||||
... 'source do_something', # list all lines of function
|
||||
... 'continue',
|
||||
... ]):
|
||||
... test_function()
|
||||
> <doctest test.test_pdb.test_list_commands[1]>(3)test_function()
|
||||
-> ret = test_function_2('baz')
|
||||
(Pdb) list
|
||||
1 def test_function():
|
||||
2 import pdb; pdb.Pdb().set_trace()
|
||||
3 -> ret = test_function_2('baz')
|
||||
[EOF]
|
||||
(Pdb) step
|
||||
--Call--
|
||||
> <doctest test.test_pdb.test_list_commands[0]>(1)test_function_2()
|
||||
-> def test_function_2(foo):
|
||||
(Pdb) list
|
||||
1 -> def test_function_2(foo):
|
||||
2 import test_pdb
|
||||
3 test_pdb.do_nothing()
|
||||
4 'some...'
|
||||
5 'more...'
|
||||
6 'code...'
|
||||
7 'to...'
|
||||
8 'make...'
|
||||
9 'a...'
|
||||
10 'long...'
|
||||
11 'listing...'
|
||||
(Pdb) list
|
||||
12 'useful...'
|
||||
13 '...'
|
||||
14 '...'
|
||||
15 return foo
|
||||
[EOF]
|
||||
(Pdb) list 1,3
|
||||
1 -> def test_function_2(foo):
|
||||
2 import test_pdb
|
||||
3 test_pdb.do_nothing()
|
||||
(Pdb) list x
|
||||
*** ...
|
||||
(Pdb) next
|
||||
> <doctest test.test_pdb.test_list_commands[0]>(2)test_function_2()
|
||||
-> import test_pdb
|
||||
(Pdb) next
|
||||
> <doctest test.test_pdb.test_list_commands[0]>(3)test_function_2()
|
||||
-> test_pdb.do_nothing()
|
||||
(Pdb) step
|
||||
--Call--
|
||||
> /home/gbr/devel/python/Lib/test/test_pdb.py(260)do_nothing()
|
||||
-> def do_nothing():
|
||||
(Pdb) longlist
|
||||
... -> def do_nothing():
|
||||
... pass
|
||||
(Pdb) source do_something
|
||||
... def do_something():
|
||||
... print(42)
|
||||
(Pdb) continue
|
||||
"""
|
||||
|
||||
|
||||
def test_pdb_skip_modules():
|
||||
"""This illustrates the simple case of module skipping.
|
||||
|
||||
|
|
|
@ -180,6 +180,7 @@ Drew Csillag
|
|||
Joaquin Cuenca Abela
|
||||
John Cugini
|
||||
Tom Culliton
|
||||
Antonio Cuni
|
||||
Brian Curtin
|
||||
Lisandro Dalcin
|
||||
Andrew Dalke
|
||||
|
|
|
@ -475,6 +475,15 @@ C-API
|
|||
Library
|
||||
-------
|
||||
|
||||
- The pdb command "source" has been added. It displays the source
|
||||
code for a given object, if possible.
|
||||
|
||||
- The pdb command "longlist" has been added. It displays the whole
|
||||
source code for the current function.
|
||||
|
||||
- Issue #1503502: Make pdb.Pdb easier to subclass by putting message
|
||||
and error output into methods.
|
||||
|
||||
- Issue #809887: Make the output of pdb's breakpoint deletions more
|
||||
consistent; emit a message when a breakpoint is enabled or disabled.
|
||||
|
||||
|
|
Loading…
Reference in New Issue