From 476bfcb353ff41d3c34fc68549f529be0c4644d9 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 10 Feb 2024 12:22:50 -0500 Subject: [PATCH] IPython console: Prevent segfault when closing and a client is debugging --- .../plugins/ipythonconsole/widgets/client.py | 23 +++++++++++++++---- .../ipythonconsole/widgets/main_widget.py | 5 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/spyder/plugins/ipythonconsole/widgets/client.py b/spyder/plugins/ipythonconsole/widgets/client.py index d868fc415c0..c132b02db35 100644 --- a/spyder/plugins/ipythonconsole/widgets/client.py +++ b/spyder/plugins/ipythonconsole/widgets/client.py @@ -23,7 +23,7 @@ # Third party imports (qtpy) from qtpy.QtCore import QUrl, QTimer, Signal, Slot -from qtpy.QtWidgets import QVBoxLayout, QWidget +from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget # Local imports from spyder.api.translations import _ @@ -121,7 +121,11 @@ def __init__(self, parent, id_, self.allow_rename = True self.error_text = None self.give_focus = give_focus + + # Attrs used when closing self.__is_last_client = False + self.__debugging_on_close = False + self.__close_now = False css_path = self.get_conf('css_path', section='appearance') if css_path is None: @@ -554,10 +558,11 @@ def set_color_scheme(self, color_scheme, reset=True): except AttributeError: pass - def close_client(self, is_last_client): + def close_client(self, is_last_client, now=False): """Close the client.""" self.__is_last_client = is_last_client - debugging = False + self.__close_now = now + self.__debugging_on_close = False # Needed to handle a RuntimeError. See spyder-ide/spyder#5568. try: @@ -566,7 +571,7 @@ def close_client(self, is_last_client): # debugging mode before closing, but also when a kernel restart is # requested while debugging. if self.shellwidget.is_debugging(): - debugging = True + self.__debugging_on_close = True self.shellwidget.sig_prompt_ready.connect(self.finish_close) self.shellwidget.stop_debugging() else: @@ -574,7 +579,7 @@ def close_client(self, is_last_client): except RuntimeError: pass - if not debugging: + if not self.__debugging_on_close: self.finish_close() def finish_close(self): @@ -587,6 +592,14 @@ def finish_close(self): except (RuntimeError, TypeError): pass + # This is a hack to prevent segfaults when closing Spyder and the + # client was debugging before doing it. + # It's a side effect of spyder-ide/spyder#21788 + if self.__debugging_on_close and self.__close_now: + for __ in range(3): + time.sleep(0.08) + QApplication.processEvents() + self.shutdown(self.__is_last_client) # Prevent errors in our tests diff --git a/spyder/plugins/ipythonconsole/widgets/main_widget.py b/spyder/plugins/ipythonconsole/widgets/main_widget.py index 0bb6165a4ab..efa8ff3161a 100644 --- a/spyder/plugins/ipythonconsole/widgets/main_widget.py +++ b/spyder/plugins/ipythonconsole/widgets/main_widget.py @@ -1767,8 +1767,9 @@ def close_all_clients(self): open_clients = self.clients.copy() for client in self.clients: is_last_client = ( - len(self.get_related_clients(client, open_clients)) == 0) - client.close_client(is_last_client) + len(self.get_related_clients(client, open_clients)) == 0 + ) + client.close_client(is_last_client, now=True) open_clients.remove(client) # Wait for all KernelHandler threads to shutdown.