Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/library/pdb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ access further features, you have to do this yourself:
.. versionadded:: 3.14
Added the *mode* argument.

.. versionchanged:: 3.14
Inline breakpoints like :func:`breakpoint` or :func:`pdb.set_trace` will
always stop the program at calling frame, ignoring the *skip* pattern (if any).

.. method:: run(statement, globals=None, locals=None)
runeval(expression, globals=None, locals=None)
runcall(function, *args, **kwds)
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,11 @@ pdb
the quit and call :func:`sys.exit`, instead of raising :exc:`bdb.BdbQuit`.
(Contributed by Tian Gao in :gh:`124704`.)

* Inline breakpoints like :func:`breakpoint` or :func:`pdb.set_trace` will
always stop the program at calling frame, ignoring the ``skip`` pattern
(if any).
(Contributed by Tian Gao in :gh:`130493`.)


pickle
------
Expand Down
9 changes: 6 additions & 3 deletions Lib/bdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,13 @@ def dispatch_opcode(self, frame, arg):
If the debugger stops on the current opcode, invoke
self.user_opcode(). Raise BdbQuit if self.quitting is set.
Return self.trace_dispatch to continue tracing in this scope.

Opcode event will always trigger the user callback. For now the only
opcode event is from an inline set_trace() and we want to stop there
unconditionally.
"""
if self.stop_here(frame) or self.break_here(frame):
self.user_opcode(frame)
if self.quitting: raise BdbQuit
self.user_opcode(frame)
if self.quitting: raise BdbQuit
return self.trace_dispatch

# Normally derived classes don't override the following
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -4341,6 +4341,28 @@ def test_quit(self):
# The quit prompt should be printed exactly twice
self.assertEqual(stdout.count("Quit anyway"), 2)

def test_set_trace_with_skip(self):
"""GH-82897
Inline set_trace() should break unconditionally. This example is a
bit oversimplified, but as `pdb.set_trace()` uses the previous Pdb
instance, it's possible that we had a previous pdb instance with
skip values when we use `pdb.set_trace()` - it would be confusing
to users when such inline breakpoints won't break immediately.
"""
script = textwrap.dedent("""
import pdb
def foo():
x = 40 + 2
pdb.Pdb(skip=['__main__']).set_trace()
foo()
""")
commands = """
p x
c
"""
stdout, _ = self._run_script(script, commands)
self.assertIn("42", stdout)


@support.requires_subprocess()
class PdbTestReadline(unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Inline breakpoints like :func:`breakpoint` or :func:`pdb.set_trace` will always stop the program at calling frame, ignoring the ``skip`` pattern (if any).
Loading