Skip to content

Commit e023091

Browse files
committed
#1437051: allow "continue"/"next"/etc. in .pdbrc, also add pdb -c option to give these commands. This allows to run a script until an exception occurs.
1 parent 1e30bd3 commit e023091

File tree

3 files changed

+72
-22
lines changed

3 files changed

+72
-22
lines changed

Doc/library/pdb.rst

+13-4
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,15 @@ example::
4444
python3 -m pdb myscript.py
4545

4646
When invoked as a script, pdb will automatically enter post-mortem debugging if
47-
the program being debugged exits abnormally. After post-mortem debugging (or
48-
after normal exit of the program), pdb will restart the program. Automatic
47+
the program being debugged exits abnormally. After post-mortem debugging (or
48+
after normal exit of the program), pdb will restart the program. Automatic
4949
restarting preserves pdb's state (such as breakpoints) and in most cases is more
5050
useful than quitting the debugger upon program's exit.
5151

52+
.. versionadded:: 3.2
53+
:file:`pdb.py` now accepts a ``-c`` option that executes commands as if given
54+
in a :file:`.pdbrc` file, see :ref:`debugger-commands`.
55+
5256
The typical usage to break into the debugger from a running program is to
5357
insert ::
5458

@@ -202,6 +206,11 @@ prompt. This is particularly useful for aliases. If both files exist, the one
202206
in the home directory is read first and aliases defined there can be overridden
203207
by the local file.
204208

209+
.. versionchanged:: 3.2
210+
:file:`.pdbrc` can now contain commands that continue debugging, such as
211+
:pdbcmd:`continue` or :pdbcmd:`next`. Previously, these commands had no
212+
effect.
213+
205214

206215
.. pdbcommand:: h(elp) [command]
207216

@@ -388,9 +397,9 @@ by the local file.
388397
As an example, here are two useful aliases (especially when placed in the
389398
:file:`.pdbrc` file)::
390399

391-
#Print instance variables (usage "pi classInst")
400+
# Print instance variables (usage "pi classInst")
392401
alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])
393-
#Print instance variables in self
402+
# Print instance variables in self
394403
alias ps pi self
395404

396405
.. pdbcommand:: unalias name

Lib/pdb.py

+55-18
Original file line numberDiff line numberDiff line change
@@ -332,19 +332,26 @@ def setup(self, f, t):
332332
# locals whenever the .f_locals accessor is called, so we
333333
# cache it here to ensure that modifications are not overwritten.
334334
self.curframe_locals = self.curframe.f_locals
335-
self.execRcLines()
335+
return self.execRcLines()
336336

337337
# Can be executed earlier than 'setup' if desired
338338
def execRcLines(self):
339-
if self.rcLines:
340-
# Make local copy because of recursion
341-
rcLines = self.rcLines
342-
# executed only once
343-
self.rcLines = []
344-
for line in rcLines:
345-
line = line[:-1]
346-
if len(line) > 0 and line[0] != '#':
347-
self.onecmd(line)
339+
if not self.rcLines:
340+
return
341+
# local copy because of recursion
342+
rcLines = self.rcLines
343+
rcLines.reverse()
344+
# execute every line only once
345+
self.rcLines = []
346+
while rcLines:
347+
line = rcLines.pop().strip()
348+
if line and line[0] != '#':
349+
if self.onecmd(line):
350+
# if onecmd returns True, the command wants to exit
351+
# from the interaction, save leftover rc lines
352+
# to execute before next interaction
353+
self.rcLines += reversed(rcLines)
354+
return True
348355

349356
# Override Bdb methods
350357

@@ -367,7 +374,7 @@ def user_line(self, frame):
367374
if self.bp_commands(frame):
368375
self.interaction(frame, None)
369376

370-
def bp_commands(self,frame):
377+
def bp_commands(self, frame):
371378
"""Call every command that was set for the current active breakpoint
372379
(if there is one).
373380
@@ -409,7 +416,11 @@ def user_exception(self, frame, exc_info):
409416
# General interaction function
410417

411418
def interaction(self, frame, traceback):
412-
self.setup(frame, traceback)
419+
if self.setup(frame, traceback):
420+
# no interaction desired at this time (happens if .pdbrc contains
421+
# a command like "continue")
422+
self.forget()
423+
return
413424
self.print_stack_entry(self.stack[self.curindex])
414425
self.cmdloop()
415426
self.forget()
@@ -1497,17 +1508,42 @@ def help():
14971508
import pydoc
14981509
pydoc.pager(__doc__)
14991510

1511+
_usage = """\
1512+
usage: pdb.py [-c command] ... pyfile [arg] ...
1513+
1514+
Debug the Python program given by pyfile.
1515+
1516+
Initial commands are read from .pdbrc files in your home directory
1517+
and in the current directory, if they exist. Commands supplied with
1518+
-c are executed after commands from .pdbrc files.
1519+
1520+
To let the script run until an exception occurs, use "-c continue".
1521+
To let the script run until a given line X in the debugged file, use
1522+
"-c 'break X' -c continue"."""
1523+
15001524
def main():
1501-
if not sys.argv[1:] or sys.argv[1] in ("--help", "-h"):
1502-
print("usage: pdb.py scriptfile [arg] ...")
1525+
import getopt
1526+
1527+
opts, args = getopt.getopt(sys.argv[1:], 'hc:', ['--help', '--command='])
1528+
1529+
if not args:
1530+
print(_usage)
15031531
sys.exit(2)
15041532

1505-
mainpyfile = sys.argv[1] # Get script filename
1533+
commands = []
1534+
for opt, optarg in opts:
1535+
if opt in ['-h', '--help']:
1536+
print(_usage)
1537+
sys.exit()
1538+
elif opt in ['-c', '--command']:
1539+
commands.append(optarg)
1540+
1541+
mainpyfile = args[0] # Get script filename
15061542
if not os.path.exists(mainpyfile):
15071543
print('Error:', mainpyfile, 'does not exist')
15081544
sys.exit(1)
15091545

1510-
del sys.argv[0] # Hide "pdb.py" from argument list
1546+
sys.argv[:] = args # Hide "pdb.py" and pdb options from argument list
15111547

15121548
# Replace pdb's dir with script's dir in front of module search path.
15131549
sys.path[0] = os.path.dirname(mainpyfile)
@@ -1517,6 +1553,7 @@ def main():
15171553
# changed by the user from the command line. There is a "restart" command
15181554
# which allows explicit specification of command line arguments.
15191555
pdb = Pdb()
1556+
pdb.rcLines.extend(commands)
15201557
while True:
15211558
try:
15221559
pdb._runscript(mainpyfile)
@@ -1525,10 +1562,10 @@ def main():
15251562
print("The program finished and will be restarted")
15261563
except Restart:
15271564
print("Restarting", mainpyfile, "with arguments:")
1528-
print("\t" + " ".join(sys.argv[1:]))
1565+
print("\t" + " ".join(args))
15291566
except SystemExit:
15301567
# In most cases SystemExit does not warrant a post-mortem session.
1531-
print("The program exited via sys.exit(). Exit status: ", end=' ')
1568+
print("The program exited via sys.exit(). Exit status:", end=' ')
15321569
print(sys.exc_info()[1])
15331570
except:
15341571
traceback.print_exc()

Misc/NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,10 @@ C-API
475475
Library
476476
-------
477477

478+
- Issue #1437051: For pdb, allow "continue" and related commands in
479+
.pdbrc files. Also, add a command-line option "-c" that runs a
480+
command as if given in .pdbrc.
481+
478482
- Issue #4179: In pdb, allow "list ." as a command to return to the
479483
currently debugged line.
480484

0 commit comments

Comments
 (0)