Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Fix errors when getting Matplotlib backend in the kernel (IPython console) #22231

Merged
merged 4 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')
Expand Down Expand Up @@ -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()
Expand Down
15 changes: 13 additions & 2 deletions spyder/plugins/ipythonconsole/utils/kernel_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()

Expand Down
20 changes: 16 additions & 4 deletions spyder/plugins/ipythonconsole/widgets/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 _
Expand Down Expand Up @@ -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)
)

Expand All @@ -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)

Expand All @@ -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:
Expand Down