Skip to content
8 changes: 7 additions & 1 deletion Doc/library/pdb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,15 @@ slightly different way:
is entered.


.. function:: set_trace(*, header=None)
.. function:: set_trace(*, header=None, commands=None)

Enter the debugger at the calling stack frame. This is useful to hard-code
a breakpoint at a given point in a program, even if the code is not
otherwise being debugged (e.g. when an assertion fails). If given,
*header* is printed to the console just before debugging begins.
The *commands* argument, if given, is a list of commands to execute
when the debugger starts.


.. versionchanged:: 3.7
The keyword-only argument *header*.
Expand All @@ -173,6 +176,9 @@ slightly different way:
:func:`set_trace` will enter the debugger immediately, rather than
on the next line of code to be executed.

.. versionadded:: 3.14
The *commands* argument.

.. function:: post_mortem(traceback=None)

Enter post-mortem debugging of the given *traceback* object. If no
Expand Down
4 changes: 2 additions & 2 deletions Lib/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,11 +389,11 @@ def __init__(self, out):
# still use input() to get user input
self.use_rawinput = 1

def set_trace(self, frame=None):
def set_trace(self, frame=None, *, commands=None):
self.__debugger_used = True
if frame is None:
frame = sys._getframe().f_back
pdb.Pdb.set_trace(self, frame)
pdb.Pdb.set_trace(self, frame, commands=commands)

def set_continue(self):
# Calling set_continue unconditionally would break unit test
Expand Down
13 changes: 9 additions & 4 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,14 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
self._chained_exceptions = tuple()
self._chained_exception_index = 0

def set_trace(self, frame=None):
def set_trace(self, frame=None, *, commands=None):
Pdb._last_pdb_instance = self
if frame is None:
frame = sys._getframe().f_back

if commands is not None:
self.rcLines.extend(commands)

super().set_trace(frame)

def sigint_handler(self, signum, frame):
Expand Down Expand Up @@ -2350,21 +2354,22 @@ def runcall(*args, **kwds):
"""
return Pdb().runcall(*args, **kwds)

def set_trace(*, header=None):
def set_trace(*, header=None, commands=None):
"""Enter the debugger at the calling stack frame.

This is useful to hard-code a breakpoint at a given point in a
program, even if the code is not otherwise being debugged (e.g. when
an assertion fails). If given, *header* is printed to the console
just before debugging begins.
just before debugging begins. *commands* is an optional list of
pdb commands to run when the debugger starts.
"""
if Pdb._last_pdb_instance is not None:
pdb = Pdb._last_pdb_instance
else:
pdb = Pdb()
if header is not None:
pdb.message(header)
pdb.set_trace(sys._getframe().f_back)
pdb.set_trace(sys._getframe().f_back, commands=commands)

# Post-Mortem interface

Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,17 @@ def test_pdb_where_command():
(Pdb) continue
"""

def test_pdb_commands_with_set_trace():
"""Test that commands can be passed to Pdb.set_trace()

>>> def test_function():
... x = 1
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace(commands=['p x', 'c'])

>>> test_function()
1
"""


# skip this test if sys.flags.no_site = True;
# exit() isn't defined unless there's a site module.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added ``commands`` argument to :func:`pdb.set_trace` which allows users to send debugger commands from the source file.