mirror of
https://github.com/python/cpython.git
synced 2025-09-27 18:59:43 +00:00
Add "longlist" and "source" commands, ideas borrowed from pdb++ by Antonio Cuni.
This commit is contained in:
parent
0d08962659
commit
e59ca2afe3
5 changed files with 179 additions and 17 deletions
|
@ -368,6 +368,12 @@ by the local file.
|
||||||
list 11 lines around at that line. With two arguments, list the given range;
|
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.
|
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)
|
.. pdbcommand:: a(rgs)
|
||||||
|
|
||||||
Print the argument list of the current function.
|
Print the argument list of the current function.
|
||||||
|
@ -385,6 +391,12 @@ by the local file.
|
||||||
|
|
||||||
Print the type of the *expression*.
|
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:
|
.. _debugger-aliases:
|
||||||
|
|
||||||
.. pdbcommand:: alias [name [command]]
|
.. pdbcommand:: alias [name [command]]
|
||||||
|
|
73
Lib/pdb.py
73
Lib/pdb.py
|
@ -74,6 +74,8 @@ import os
|
||||||
import re
|
import re
|
||||||
import pprint
|
import pprint
|
||||||
import traceback
|
import traceback
|
||||||
|
import inspect
|
||||||
|
import types
|
||||||
|
|
||||||
|
|
||||||
class Restart(Exception):
|
class Restart(Exception):
|
||||||
|
@ -1028,25 +1030,62 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
filename = self.curframe.f_code.co_filename
|
filename = self.curframe.f_code.co_filename
|
||||||
breaklist = self.get_file_breaks(filename)
|
breaklist = self.get_file_breaks(filename)
|
||||||
try:
|
try:
|
||||||
for lineno in range(first, last+1):
|
# XXX add tb_lineno feature
|
||||||
line = linecache.getline(filename, lineno,
|
lines = linecache.getlines(filename, self.curframe.f_globals)
|
||||||
self.curframe.f_globals)
|
self._print_lines(lines[first-1:last], first, breaklist,
|
||||||
if not line:
|
self.curframe.f_lineno, -1)
|
||||||
|
self.lineno = min(last, len(lines))
|
||||||
|
if len(lines) < last:
|
||||||
self.message('[EOF]')
|
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
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
do_l = do_list
|
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):
|
def do_whatis(self, arg):
|
||||||
"""whatis arg
|
"""whatis arg
|
||||||
Print the type of the argument.
|
Print the type of the argument.
|
||||||
|
@ -1249,10 +1288,12 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
_help_order = [
|
_help_order = [
|
||||||
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
|
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
|
||||||
'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
|
'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
|
||||||
'jump', 'return', 'retval', 'run', 'continue', 'list', 'args', 'print',
|
'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
|
||||||
'whatis', 'alias', 'unalias', 'quit',
|
'args', 'print', 'pp', 'whatis', 'source', 'alias', 'unalias',
|
||||||
|
'debug', 'quit',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
docs = set()
|
||||||
for _command in _help_order:
|
for _command in _help_order:
|
||||||
__doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
|
__doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
|
||||||
__doc__ += Pdb.help_exec.__doc__
|
__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():
|
def test_pdb_skip_modules():
|
||||||
"""This illustrates the simple case of module skipping.
|
"""This illustrates the simple case of module skipping.
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,7 @@ Drew Csillag
|
||||||
Joaquin Cuenca Abela
|
Joaquin Cuenca Abela
|
||||||
John Cugini
|
John Cugini
|
||||||
Tom Culliton
|
Tom Culliton
|
||||||
|
Antonio Cuni
|
||||||
Brian Curtin
|
Brian Curtin
|
||||||
Lisandro Dalcin
|
Lisandro Dalcin
|
||||||
Andrew Dalke
|
Andrew Dalke
|
||||||
|
|
|
@ -475,6 +475,15 @@ C-API
|
||||||
Library
|
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
|
- Issue #809887: Make the output of pdb's breakpoint deletions more
|
||||||
consistent; emit a message when a breakpoint is enabled or disabled.
|
consistent; emit a message when a breakpoint is enabled or disabled.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue