Repository: spyder-ide/spyder

Issue:
New breakpoints can't be created in the IPython console
## Description

**What steps will reproduce the problem?**
1. create a breakpoint, start debugging, and continue to the next breakpoint
2. during the interactive ipdb sessions, add a second breakpoint further down the road
3. continue execution

**What is the expected output? What do you see instead?**
I expect the debugger to pause at the second breakpoint. Instead it ignores it (i.e. all breakpoints need to be specified _before_ debugging)

**Please provide any additional information below**
## Version and main components
- Spyder Version: 3.0.0 
- Python Version: 3.4.5
- Qt Versions: 4.8.7, PyQt4 (API v2) 4.11.4 on Darwin
## Dependencies

```
pyflakes >=0.6.0 :  1.3.0 (OK)
pep8 >=0.6       :  1.7.0 (OK)
pygments >=2.0   :  2.1.3 (OK)
qtconsole >=4.2.0:  4.2.1 (OK)
nbconvert >=4.0  :  4.2.0 (OK)
pandas >=0.13.1  :  0.18.1 (OK)
numpy >=1.7      :  1.11.1 (OK)
sphinx >=0.6.6   :  1.4.6 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
jedi >=0.8.1     :  0.9.0 (OK)
psutil >=0.3     :  4.3.1 (OK)
matplotlib >=1.0 :  1.5.1 (OK)
sympy >=0.7.3    :  1.0 (OK)
pylint >=0.25    :  1.6.4 (OK)

```



Discussion:
Thanks for reporting. I'm aware of this problem but I didn't have time to fix it for 3.0.

Sure, I understand. My plethora of bug reports simply shows my excitement for the new version :)

> On Sep 29, 2016, at 00:25, Carlos Cordoba notifications@github.com wrote:
> 
> Thanks for reporting. I'm aware of this problem but I didn't have time to fix it for 3.0.
> 
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub, or mute the thread.

@rlaverde, please solve this one this week. Take a look at PR #3561 to understand how to proceed.

Resolving patch:
diff --git a/spyder/plugins/ipythonconsole.py b/spyder/plugins/ipythonconsole.py
--- a/spyder/plugins/ipythonconsole.py
+++ b/spyder/plugins/ipythonconsole.py
@@ -794,6 +794,7 @@ def register_plugin(self):
                          lambda fname, lineno, word, processevents:
                              self.editor.load(fname, lineno, word,
                                               processevents=processevents))
+        self.editor.breakpoints_saved.connect(self.set_spyder_breakpoints)
         self.editor.run_in_current_ipyclient.connect(
                                          self.run_script_in_current_client)
         self.main.workingdirectory.set_current_console_wd.connect(
@@ -1215,6 +1216,11 @@ def pdb_has_stopped(self, fname, lineno, shellwidget):
         self.activateWindow()
         shellwidget._control.setFocus()
 
+    def set_spyder_breakpoints(self):
+        """Set Spyder breakpoints into all clients"""
+        for cl in self.clients:
+            cl.shellwidget.set_spyder_breakpoints()
+
     #------ Public API (for kernels) ------------------------------------------
     def ssh_tunnel(self, *args, **kwargs):
         if os.name == 'nt':
diff --git a/spyder/utils/ipython/spyder_kernel.py b/spyder/utils/ipython/spyder_kernel.py
--- a/spyder/utils/ipython/spyder_kernel.py
+++ b/spyder/utils/ipython/spyder_kernel.py
@@ -83,7 +83,7 @@ def _pdb_locals(self):
             return {}
 
     # -- Public API ---------------------------------------------------
-    # For the Variable Explorer
+    # --- For the Variable Explorer
     def get_namespace_view(self):
         """
         Return the namespace view
@@ -329,6 +329,12 @@ def _register_pdb_session(self, pdb_obj):
         """Register Pdb session to use it later"""
         self._pdb_obj = pdb_obj
 
+    def _set_spyder_breakpoints(self):
+        """Set all Spyder breakpoints in an active pdb session"""
+        if not self._pdb_obj:
+            return
+        self._pdb_obj.set_spyder_breakpoints()
+
     # --- For the Help plugin
     def _eval(self, text):
         """
diff --git a/spyder/widgets/ipythonconsole/debugging.py b/spyder/widgets/ipythonconsole/debugging.py
--- a/spyder/widgets/ipythonconsole/debugging.py
+++ b/spyder/widgets/ipythonconsole/debugging.py
@@ -72,6 +72,12 @@ def write_to_stdin(self, line):
         # Run post exec commands
         self._post_exec_input(line)
 
+    def set_spyder_breakpoints(self):
+        """Set Spyder breakpoints into a debugging session"""
+        if self._reading:
+            self.kernel_client.input(
+                "!get_ipython().kernel._set_spyder_breakpoints()")
+
     # ---- Private API (defined by us) -------------------------------
     def _post_exec_input(self, line):
         """Commands to be run after writing to stdin"""


Test patch:
diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py
--- a/spyder/app/tests/test_mainwindow.py
+++ b/spyder/app/tests/test_mainwindow.py
@@ -78,6 +78,43 @@ def close_widget():
 #==============================================================================
 # Tests
 #==============================================================================
+@flaky(max_runs=10)
+@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows")
+def test_set_new_breakpoints(main_window, qtbot):
+    """Test that new breakpoints are set in the IPython console."""
+    # Wait until the window is fully up
+    shell = main_window.ipyconsole.get_current_shellwidget()
+    control = shell._control
+    qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT)
+
+    # Clear all breakpoints
+    main_window.editor.clear_all_breakpoints()
+
+    # Load test file
+    test_file = osp.join(LOCATION, 'script.py')
+    main_window.editor.load(test_file)
+
+    # Click the debug button
+    debug_action = main_window.debug_toolbar_actions[0]
+    debug_button = main_window.debug_toolbar.widgetForAction(debug_action)
+    qtbot.mouseClick(debug_button, Qt.LeftButton)
+    qtbot.wait(1000)
+
+    # Set a breakpoint
+    code_editor = main_window.editor.get_focus_widget()
+    code_editor.add_remove_breakpoint(line_number=6)
+    qtbot.wait(500)
+
+    # Verify that the breakpoint was set
+    shell.kernel_client.input("b")
+    qtbot.wait(500)
+    assert "1   breakpoint   keep yes   at {}:6".format(test_file) in control.toPlainText()
+
+    # Remove breakpoint and close test file
+    main_window.editor.clear_all_breakpoints()
+    main_window.editor.close_file()
+
+
 @flaky(max_runs=10)
 @pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows")
 def test_run_code(main_window, qtbot):