Repository: spyder-ide/spyder

Issue:
Startup script for debugger
Is it possible to set one? I have functions useful for debugging that I placed in `Preferences > IPython console > Startup > Run a file`, but they're are undefined in `ipdb>`. Further, running debugger appears to _undo_ the startup script; I can access functions before running debugger, but not after (unless I restart kernel).

I figure this isn't as simple due to debugger namespace scoping, so I suppose the question's rather whether there's a way to define _global_ functions - but that IPython "forgets" the startup script after debugging remains unclear to me.


Discussion:
I think this is an idea worth exploring. @impact27, what do you think about it?
Something like https://github.com/spyder-ide/spyder/pull/10542? I really like this PR :) I use it to load matplotlib and numpy in every frame I debug.
That's it! Sorry Quentin for not reviewing that one (I forgot about it). I'll merge it for sure for 4.2.0.

Resolving patch:
diff --git a/spyder/plugins/ipythonconsole/confpage.py b/spyder/plugins/ipythonconsole/confpage.py
--- a/spyder/plugins/ipythonconsole/confpage.py
+++ b/spyder/plugins/ipythonconsole/confpage.py
@@ -220,6 +220,23 @@ def setup_page(self):
         run_lines_layout.addWidget(run_lines_edit)
         run_lines_group.setLayout(run_lines_layout)
 
+        # Pdb run lines Group
+        pdb_run_lines_group = QGroupBox(_("Run code while debugging"))
+        pdb_run_lines_label = QLabel(_(
+            "You can run several lines of code on each "
+            "new prompt while debugging. Please "
+            "introduce each one separated by semicolons "
+            "and a space, for example:<br>"
+            "<i>import matplotlib.pyplot as plt</i>"))
+        pdb_run_lines_label.setWordWrap(True)
+        pdb_run_lines_edit = self.create_lineedit(
+            _("Lines:"), 'startup/pdb_run_lines', '', alignment=Qt.Horizontal)
+
+        pdb_run_lines_layout = QVBoxLayout()
+        pdb_run_lines_layout.addWidget(pdb_run_lines_label)
+        pdb_run_lines_layout.addWidget(pdb_run_lines_edit)
+        pdb_run_lines_group.setLayout(pdb_run_lines_layout)
+
         # Run file Group
         run_file_group = QGroupBox(_("Run a file"))
         run_file_label = QLabel(_("You can also run a whole file at startup "
@@ -374,7 +391,8 @@ def setup_page(self):
                                     source_code_group), _("Display"))
         tabs.addTab(self.create_tab(pylab_group, backend_group, inline_group),
                     _("Graphics"))
-        tabs.addTab(self.create_tab(run_lines_group, run_file_group),
+        tabs.addTab(self.create_tab(run_lines_group, pdb_run_lines_group,
+                                    run_file_group),
                     _("Startup"))
         tabs.addTab(self.create_tab(jedi_group, greedy_group, autocall_group,
                                     sympy_group, prompts_group,
diff --git a/spyder/plugins/ipythonconsole/widgets/debugging.py b/spyder/plugins/ipythonconsole/widgets/debugging.py
--- a/spyder/plugins/ipythonconsole/widgets/debugging.py
+++ b/spyder/plugins/ipythonconsole/widgets/debugging.py
@@ -371,6 +371,13 @@ def _handle_input_request(self, msg):
         if self.is_waiting_pdb_input():
             self._pdb_input_ready = True
 
+        start_line = CONF.get('ipython_console', 'startup/pdb_run_lines', '')
+        # Only run these lines when printing a new prompt
+        if start_line and print_prompt and self.is_waiting_pdb_input():
+            # Send a few commands
+            self.pdb_execute(start_line, hidden=True)
+            return
+
         # While the widget thinks only one input is going on,
         # other functions can be sending messages to the kernel.
         # This must be properly processed to avoid dropping messages.


Test patch:
diff --git a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
--- a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
+++ b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
@@ -1717,5 +1717,31 @@ def test_stderr_poll(ipyconsole, qtbot):
     assert "test_test" in ipyconsole.get_focus_widget().toPlainText()
 
 
+@pytest.mark.slow
+@pytest.mark.use_startup_wdir
+def test_startup_code_pdb(ipyconsole, qtbot):
+    """Test that startup code for pdb works."""
+    shell = ipyconsole.get_current_shellwidget()
+    qtbot.waitUntil(lambda: shell._prompt_html is not None,
+                    timeout=SHELL_TIMEOUT)
+
+    # Give focus to the widget that's going to receive clicks
+    control = ipyconsole.get_focus_widget()
+    control.setFocus()
+
+    # Run a line on startup
+    CONF.set('ipython_console', 'startup/pdb_run_lines',
+             'abba = 12; print("Hello")')
+
+    shell.execute('%debug print()')
+    qtbot.waitUntil(lambda: 'Hello' in control.toPlainText())
+
+    # Verify that the line was executed
+    assert shell.get_value('abba') == 12
+
+    # Reset setting
+    CONF.set('ipython_console', 'startup/pdb_run_lines', '')
+
+
 if __name__ == "__main__":
     pytest.main()
diff --git a/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py b/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py
--- a/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py
+++ b/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py
@@ -239,6 +239,9 @@ def test_arrayeditor_edit_2d_array(qtbot):
     assert np.sum(diff_arr != dlg.get_value()) == 2
 
 
+@pytest.mark.skipif(
+    sys.platform.startswith('linux'),
+    reason="Sometimes fails on Linux ")
 @pytest.mark.slow
 def test_arrayeditor_edit_complex_array(qtbot):
     """See: spyder-ide/spyder#7848"""