summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorSenthil Kumaran <senthil@uthcode.com>2012-05-01 02:37:11 (GMT)
committerSenthil Kumaran <senthil@uthcode.com>2012-05-01 02:37:11 (GMT)
commit417c3848d5a594941ca19c73790f5339a1eebcb9 (patch)
tree8d68c3631338af067fa770453f3da2976bccf922 /Lib
parent34d94a21018e8172f4e57a96fb537427f9dbb251 (diff)
parent42d7081806444582ee20f6cfdf7e8c88b165b0b0 (diff)
downloadcpython-417c3848d5a594941ca19c73790f5339a1eebcb9.zip
cpython-417c3848d5a594941ca19c73790f5339a1eebcb9.tar.gz
cpython-417c3848d5a594941ca19c73790f5339a1eebcb9.tar.bz2
issue13183 - Fix pdb skipping frames after hitting a breakpoint and running step. Patch by Xavier de Gaye
Diffstat (limited to 'Lib')
-rw-r--r--Lib/bdb.py15
-rw-r--r--Lib/test/test_pdb.py51
2 files changed, 65 insertions, 1 deletions
diff --git a/Lib/bdb.py b/Lib/bdb.py
index f711004..dd1f4287 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -22,6 +22,7 @@ class Bdb:
self.skip = set(skip) if skip else None
self.breaks = {}
self.fncache = {}
+ self.frame_returning = None
def canonic(self, filename):
if filename == "<" + filename[1:-1] + ">":
@@ -80,7 +81,11 @@ class Bdb:
def dispatch_return(self, frame, arg):
if self.stop_here(frame) or frame == self.returnframe:
- self.user_return(frame, arg)
+ try:
+ self.frame_returning = frame
+ self.user_return(frame, arg)
+ finally:
+ self.frame_returning = None
if self.quitting: raise BdbQuit
return self.trace_dispatch
@@ -186,6 +191,14 @@ class Bdb:
def set_step(self):
"""Stop after one line of code."""
+ # Issue #13183: pdb skips frames after hitting a breakpoint and running
+ # step commands.
+ # Restore the trace function in the caller (that may not have been set
+ # for performance reasons) when returning from the current frame.
+ if self.frame_returning:
+ caller_frame = self.frame_returning.f_back
+ if caller_frame and not caller_frame.f_trace:
+ caller_frame.f_trace = self.trace_dispatch
self._set_stopinfo(None, None)
def set_next(self, frame):
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index c197aff..ac92931 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -5,6 +5,7 @@ import pdb
import sys
import unittest
import subprocess
+import textwrap
from test import support
# This little helper class is essential for testing pdb under doctest.
@@ -598,6 +599,22 @@ def test_pdb_run_with_code_object():
class PdbTestCase(unittest.TestCase):
+ def run_pdb(self, script, commands):
+ """Run 'script' lines with pdb and the pdb 'commands'."""
+ filename = 'main.py'
+ with open(filename, 'w') as f:
+ f.write(textwrap.dedent(script))
+ cmd = [sys.executable, '-m', 'pdb', filename]
+ stdout = stderr = None
+ with subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ ) as proc:
+ stdout, stderr = proc.communicate(str.encode(commands))
+ stdout = stdout and bytes.decode(stdout)
+ stderr = stderr and bytes.decode(stderr)
+ return stdout, stderr
+
def test_issue7964(self):
# open the file as binary so we can force \r\n newline
with open(support.TESTFN, 'wb') as f:
@@ -613,6 +630,40 @@ class PdbTestCase(unittest.TestCase):
self.assertNotIn(b'SyntaxError', stdout,
"Got a syntax error running test script under PDB")
+ def test_issue13183(self):
+ script = """
+ from bar import bar
+
+ def foo():
+ bar()
+
+ def nope():
+ pass
+
+ def foobar():
+ foo()
+ nope()
+
+ foobar()
+ """
+ commands = """
+ from bar import bar
+ break bar
+ continue
+ step
+ step
+ quit
+ """
+ bar = """
+ def bar():
+ print('1')
+ """
+ with open('bar.py', 'w') as f:
+ f.write(textwrap.dedent(bar))
+ stdout, stderr = self.run_pdb(script, commands)
+ self.assertIn('main.py(5)foo()->None', stdout.split('\n')[-3],
+ 'Fail to step into the caller after a return')
+
def tearDown(self):
support.unlink(support.TESTFN)