Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e59ca2a

Browse files
committed
Add "longlist" and "source" commands, ideas borrowed from pdb++ by Antonio Cuni.
1 parent 0d08962 commit e59ca2a

5 files changed

Lines changed: 179 additions & 17 deletions

File tree

Doc/library/pdb.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,12 @@ by the local file.
368368
list 11 lines around at that line. With two arguments, list the given range;
369369
if the second argument is less than the first, it is interpreted as a count.
370370

371+
.. pdbcommand:: ll | longlist
372+
373+
List all source code for the current function or frame.
374+
375+
.. versionadded:: 3.2
376+
371377
.. pdbcommand:: a(rgs)
372378

373379
Print the argument list of the current function.
@@ -385,6 +391,12 @@ by the local file.
385391

386392
Print the type of the *expression*.
387393

394+
.. pdbcommand:: source expression
395+
396+
Try to get source code for the given object and display it.
397+
398+
.. versionadded:: 3.2
399+
388400
.. _debugger-aliases:
389401

390402
.. pdbcommand:: alias [name [command]]

Lib/pdb.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@
7474
import re
7575
import pprint
7676
import traceback
77+
import inspect
78+
import types
7779

7880

7981
class Restart(Exception):
@@ -1028,25 +1030,62 @@ def do_list(self, arg):
10281030
filename = self.curframe.f_code.co_filename
10291031
breaklist = self.get_file_breaks(filename)
10301032
try:
1031-
for lineno in range(first, last+1):
1032-
line = linecache.getline(filename, lineno,
1033-
self.curframe.f_globals)
1034-
if not line:
1035-
self.message('[EOF]')
1036-
break
1037-
else:
1038-
s = repr(lineno).rjust(3)
1039-
if len(s) < 4: s = s + ' '
1040-
if lineno in breaklist: s = s + 'B'
1041-
else: s = s + ' '
1042-
if lineno == self.curframe.f_lineno:
1043-
s = s + '->'
1044-
self.message(s + '\t' + line.rstrip())
1045-
self.lineno = lineno
1033+
# XXX add tb_lineno feature
1034+
lines = linecache.getlines(filename, self.curframe.f_globals)
1035+
self._print_lines(lines[first-1:last], first, breaklist,
1036+
self.curframe.f_lineno, -1)
1037+
self.lineno = min(last, len(lines))
1038+
if len(lines) < last:
1039+
self.message('[EOF]')
10461040
except KeyboardInterrupt:
10471041
pass
10481042
do_l = do_list
10491043

1044+
def do_longlist(self, arg):
1045+
"""longlist | ll
1046+
List the whole source code for the current function or frame.
1047+
"""
1048+
filename = self.curframe.f_code.co_filename
1049+
breaklist = self.get_file_breaks(filename)
1050+
try:
1051+
lines, lineno = inspect.getsourcelines(self.curframe)
1052+
except IOError as err:
1053+
self.error(err)
1054+
return
1055+
self._print_lines(lines, lineno, breaklist, self.curframe.f_lineno, -1)
1056+
do_ll = do_longlist
1057+
1058+
def do_source(self, arg):
1059+
"""source expression
1060+
Try to get source code for the given object and display it.
1061+
"""
1062+
try:
1063+
obj = self._getval(arg)
1064+
except:
1065+
return
1066+
try:
1067+
lines, lineno = inspect.getsourcelines(obj)
1068+
except (IOError, TypeError) as err:
1069+
self.error(err)
1070+
return
1071+
self._print_lines(lines, lineno, [], -1, -1)
1072+
1073+
def _print_lines(self, lines, start, breaks, current, special):
1074+
"""Print a range of lines."""
1075+
for lineno, line in enumerate(lines, start):
1076+
s = str(lineno).rjust(3)
1077+
if len(s) < 4:
1078+
s += ' '
1079+
if lineno in breaks:
1080+
s += 'B'
1081+
else:
1082+
s += ' '
1083+
if lineno == current:
1084+
s += '->'
1085+
elif lineno == special:
1086+
s += '>>'
1087+
self.message(s + '\t' + line.rstrip())
1088+
10501089
def do_whatis(self, arg):
10511090
"""whatis arg
10521091
Print the type of the argument.
@@ -1249,10 +1288,12 @@ def _runscript(self, filename):
12491288
_help_order = [
12501289
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
12511290
'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
1252-
'jump', 'return', 'retval', 'run', 'continue', 'list', 'args', 'print',
1253-
'whatis', 'alias', 'unalias', 'quit',
1291+
'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
1292+
'args', 'print', 'pp', 'whatis', 'source', 'alias', 'unalias',
1293+
'debug', 'quit',
12541294
]
12551295

1296+
docs = set()
12561297
for _command in _help_order:
12571298
__doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
12581299
__doc__ += Pdb.help_exec.__doc__

Lib/test/test_pdb.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,105 @@ def test_pdb_breakpoint_commands():
257257
"""
258258

259259

260+
def do_nothing():
261+
pass
262+
263+
def do_something():
264+
print(42)
265+
266+
def test_list_commands():
267+
"""Test the list and source commands of pdb.
268+
269+
>>> def test_function_2(foo):
270+
... import test_pdb
271+
... test_pdb.do_nothing()
272+
... 'some...'
273+
... 'more...'
274+
... 'code...'
275+
... 'to...'
276+
... 'make...'
277+
... 'a...'
278+
... 'long...'
279+
... 'listing...'
280+
... 'useful...'
281+
... '...'
282+
... '...'
283+
... return foo
284+
285+
>>> def test_function():
286+
... import pdb; pdb.Pdb().set_trace()
287+
... ret = test_function_2('baz')
288+
289+
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
290+
... 'list', # list first function
291+
... 'step', # step into second function
292+
... 'list', # list second function
293+
... 'list', # continue listing to EOF
294+
... 'list 1,3', # list specific lines
295+
... 'list x', # invalid argument
296+
... 'next', # step to import
297+
... 'next', # step over import
298+
... 'step', # step into do_nothing
299+
... 'longlist', # list all lines
300+
... 'source do_something', # list all lines of function
301+
... 'continue',
302+
... ]):
303+
... test_function()
304+
> <doctest test.test_pdb.test_list_commands[1]>(3)test_function()
305+
-> ret = test_function_2('baz')
306+
(Pdb) list
307+
1 def test_function():
308+
2 import pdb; pdb.Pdb().set_trace()
309+
3 -> ret = test_function_2('baz')
310+
[EOF]
311+
(Pdb) step
312+
--Call--
313+
> <doctest test.test_pdb.test_list_commands[0]>(1)test_function_2()
314+
-> def test_function_2(foo):
315+
(Pdb) list
316+
1 -> def test_function_2(foo):
317+
2 import test_pdb
318+
3 test_pdb.do_nothing()
319+
4 'some...'
320+
5 'more...'
321+
6 'code...'
322+
7 'to...'
323+
8 'make...'
324+
9 'a...'
325+
10 'long...'
326+
11 'listing...'
327+
(Pdb) list
328+
12 'useful...'
329+
13 '...'
330+
14 '...'
331+
15 return foo
332+
[EOF]
333+
(Pdb) list 1,3
334+
1 -> def test_function_2(foo):
335+
2 import test_pdb
336+
3 test_pdb.do_nothing()
337+
(Pdb) list x
338+
*** ...
339+
(Pdb) next
340+
> <doctest test.test_pdb.test_list_commands[0]>(2)test_function_2()
341+
-> import test_pdb
342+
(Pdb) next
343+
> <doctest test.test_pdb.test_list_commands[0]>(3)test_function_2()
344+
-> test_pdb.do_nothing()
345+
(Pdb) step
346+
--Call--
347+
> /home/gbr/devel/python/Lib/test/test_pdb.py(260)do_nothing()
348+
-> def do_nothing():
349+
(Pdb) longlist
350+
... -> def do_nothing():
351+
... pass
352+
(Pdb) source do_something
353+
... def do_something():
354+
... print(42)
355+
(Pdb) continue
356+
"""
357+
358+
260359
def test_pdb_skip_modules():
261360
"""This illustrates the simple case of module skipping.
262361

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ Drew Csillag
180180
Joaquin Cuenca Abela
181181
John Cugini
182182
Tom Culliton
183+
Antonio Cuni
183184
Brian Curtin
184185
Lisandro Dalcin
185186
Andrew Dalke

Misc/NEWS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,15 @@ C-API
475475
Library
476476
-------
477477

478+
- The pdb command "source" has been added. It displays the source
479+
code for a given object, if possible.
480+
481+
- The pdb command "longlist" has been added. It displays the whole
482+
source code for the current function.
483+
484+
- Issue #1503502: Make pdb.Pdb easier to subclass by putting message
485+
and error output into methods.
486+
478487
- Issue #809887: Make the output of pdb's breakpoint deletions more
479488
consistent; emit a message when a breakpoint is enabled or disabled.
480489

0 commit comments

Comments
 (0)