diff --git a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py index e28819f13ee..27d8171b5ec 100644 --- a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py +++ b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py @@ -1923,7 +1923,6 @@ def test_pdb_comprehension_namespace(ipyconsole, qtbot, tmpdir): @flaky(max_runs=10) @pytest.mark.auto_backend -@pytest.mark.skipif(os.name == 'nt', reason="Fails on windows") def test_restart_interactive_backend(ipyconsole, qtbot): """ Test that we ask for a restart or not after switching to different @@ -1936,7 +1935,8 @@ def test_restart_interactive_backend(ipyconsole, qtbot): # This is necessary to test no spurious messages are printed to the console shell.clear_console() - qtbot.waitUntil(lambda: '\nIn [2]: ' == shell._control.toPlainText()) + empty_console_text = '\n\nIn [2]: ' if os.name == "nt" else '\nIn [2]: ' + qtbot.waitUntil(lambda: empty_console_text == shell._control.toPlainText()) # Switch to the tk backend ipyconsole.set_conf('pylab/backend', 'tk') @@ -1967,7 +1967,7 @@ def test_restart_interactive_backend(ipyconsole, qtbot): assert bool(os.environ.get('BACKEND_REQUIRE_RESTART')) # Check we no spurious messages are shown before the restart below - assert "\nIn [2]: " == shell._control.toPlainText() + assert empty_console_text == shell._control.toPlainText() # Restart kernel to check if the new interactive backend is set ipyconsole.restart_kernel() diff --git a/spyder/plugins/ipythonconsole/utils/kernel_handler.py b/spyder/plugins/ipythonconsole/utils/kernel_handler.py index 795008156f5..b74fd4c9bb4 100644 --- a/spyder/plugins/ipythonconsole/utils/kernel_handler.py +++ b/spyder/plugins/ipythonconsole/utils/kernel_handler.py @@ -201,8 +201,14 @@ def connect_(self): self._shellwidget_connected = True # Emit signal in case the connection is already made if self.connection_state in [ - KernelConnectionState.IpykernelReady, - KernelConnectionState.SpyderKernelReady]: + KernelConnectionState.IpykernelReady, + KernelConnectionState.SpyderKernelReady + ]: + # This is necessary for systems in which the kernel takes too much + # time to start because in that case its heartbeat is not detected + # as beating at this point. + # Fixes spyder-ide/spyder#22179 + self.kernel_client.hb_channel._beating = True self.sig_kernel_is_ready.emit() elif self.connection_state == KernelConnectionState.Error: self.sig_kernel_connection_error.emit() @@ -274,6 +280,11 @@ def handle_comm_ready(self): KernelConnectionState.SpyderKernelWaitComm, KernelConnectionState.Crashed ]: + # This is necessary for systems in which the kernel takes too much + # time to start because in that case its heartbeat is not detected + # as beating at this point. + # Fixes spyder-ide/spyder#22179 + self.kernel_client.hb_channel._beating = True self.connection_state = KernelConnectionState.SpyderKernelReady self.sig_kernel_is_ready.emit() diff --git a/spyder/plugins/ipythonconsole/widgets/status.py b/spyder/plugins/ipythonconsole/widgets/status.py index 71a0b8b8008..b8b8286b6f6 100644 --- a/spyder/plugins/ipythonconsole/widgets/status.py +++ b/spyder/plugins/ipythonconsole/widgets/status.py @@ -7,9 +7,13 @@ """Status bar widgets.""" # Standard library imports +import functools import sys import textwrap +# Third-party imports +from spyder_kernels.comms.frontendcomm import CommError + # Local imports from spyder.api.shellconnect.mixins import ShellConnectMixin from spyder.api.translations import _ @@ -100,9 +104,11 @@ def update_status(self, gui): def add_shellwidget(self, shellwidget): """Add shellwidget.""" shellwidget.sig_config_spyder_kernel.connect( - lambda sw=shellwidget: self.config_spyder_kernel(sw) + functools.partial(self.config_spyder_kernel, shellwidget) ) shellwidget.kernel_handler.sig_kernel_is_ready.connect( + # We can't use functools.partial here because it gives memory leaks + # in Python versions older than 3.10 lambda sw=shellwidget: self.on_kernel_start(sw) ) @@ -117,8 +123,9 @@ def add_shellwidget(self, shellwidget): def config_spyder_kernel(self, shellwidget): shellwidget.kernel_handler.kernel_comm.register_call_handler( "update_matplotlib_gui", - lambda gui, sid=id(shellwidget): - self.update_matplotlib_gui(gui, sid) + functools.partial( + self.update_matplotlib_gui, shellwidget_id=id(shellwidget) + ) ) shellwidget.set_kernel_configuration("update_gui", True) @@ -133,7 +140,12 @@ def on_kernel_start(self, shellwidget): if running_in_ci() and not sys.platform.startswith("linux"): mpl_backend = "inline" else: - mpl_backend = shellwidget.get_matplotlib_backend() + # Needed when the comm is not connected. + # Fixes spyder-ide/spyder#22194 + try: + mpl_backend = shellwidget.get_matplotlib_backend() + except CommError: + mpl_backend = None # Hide widget if Matplotlib is not available or failed to import if mpl_backend is None: