diff --git a/python/helpers/pydev/_pydevd_frame_eval/pydevd_frame_tracing.py b/python/helpers/pydev/_pydevd_frame_eval/pydevd_frame_tracing.py index ec00417250aa..e079e5757a42 100644 --- a/python/helpers/pydev/_pydevd_frame_eval/pydevd_frame_tracing.py +++ b/python/helpers/pydev/_pydevd_frame_eval/pydevd_frame_tracing.py @@ -61,10 +61,17 @@ def handle_breakpoint(frame, info, global_debugger, breakpoint): return True +def _get_line_for_frame(frame): + # it's absolutely necessary to reset tracing function for frame in order to get the real line number + tracing_func = frame.f_trace + frame.f_trace = None + line = frame.f_lineno + frame.f_trace = tracing_func + return line + + def _pydev_stop_at_break(): frame = sys._getframe(1) - # it's absolutely necessary to reset tracing function for frame in order to get the real line number - frame.f_trace = None t = threading.currentThread() if t.additional_info.is_tracing: return @@ -81,14 +88,14 @@ def _pydev_stop_at_break(): filename = abs_path_real_path_and_base[1] breakpoints_for_file = debugger.breakpoints.get(filename) - line = frame.f_lineno + line = _get_line_for_frame(frame) try: breakpoint = breakpoints_for_file[line] except KeyError: - pydev_log.debug("Couldn't find breakpoint in the file {} on line {}".format(frame.f_code.co_filename, frame.f_lineno)) + pydev_log.debug("Couldn't find breakpoint in the file {} on line {}".format(frame.f_code.co_filename, line)) return if breakpoint and handle_breakpoint(frame, t.additional_info, debugger, breakpoint): - pydev_log.debug("Suspending at breakpoint in file: {} on line {}".format(frame.f_code.co_filename, frame.f_lineno)) + pydev_log.debug("Suspending at breakpoint in file: {} on line {}".format(frame.f_code.co_filename, line)) debugger.set_suspend(t, CMD_SET_BREAK) debugger.do_wait_suspend(t, frame, 'line', None) diff --git a/python/testData/debug/test_resume_after_step.py b/python/testData/debug/test_resume_after_step.py new file mode 100644 index 000000000000..f5cb1d8933c6 --- /dev/null +++ b/python/testData/debug/test_resume_after_step.py @@ -0,0 +1,16 @@ +def foo(): + a = 1 + b = 2 # breakpoint + c = 3 + d = 4 + e = 5 # breakpoint + return a + b + + +def main(): + foo() + t = 1 + s = 12 # breakpoint + + +main() diff --git a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java index 2aff5eb64b18..dbc05c5fa578 100644 --- a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java +++ b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java @@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.xdebugger.XDebuggerTestUtil; @@ -31,7 +29,6 @@ import com.jetbrains.python.sdkTools.SdkCreationType; import org.jetbrains.annotations.NotNull; import org.junit.Test; -import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -1102,6 +1099,39 @@ public class PythonDebuggerTest extends PyEnvTestCase { }); } + @Staging + @Test + public void testResumeAfterStepping() throws Exception { + // This test case is important for frame evaluation debugging, because we reuse old tracing function for stepping and there were + // some problems with switching between frame evaluation and tracing + runPythonTest(new PyDebuggerTask("/debug", "test_resume_after_step.py") { + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptName(), 2); + toggleBreakpoint(getScriptName(), 5); + toggleBreakpoint(getScriptName(), 12); + } + + @Override + public void testing() throws Exception { + waitForPause(); + eval("a").hasValue("1"); + stepOver(); + waitForPause(); + stepOver(); + waitForPause(); + eval("c").hasValue("3"); + resume(); + waitForPause(); + eval("d").hasValue("4"); + resume(); + waitForPause(); + eval("t").hasValue("1"); + resume(); + } + }); + } + //TODO: That doesn't work now: case from test_continuation.py and test_continuation2.py are treated differently by interpreter // (first line is executed in first case and last line in second)