Skip to content

Commit c105eab

Browse files
committed
Excepthook workaround for IPython
1 parent d5ddd23 commit c105eab

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

puzzlepiece/puzzle.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,27 @@ def __init__(self, app, name, debug=True, *args, **kwargs):
3737

3838
self.wrapper_layout.addLayout(self._button_layout(), 1, 0)
3939

40-
sys.excepthook = self._excepthook
40+
# This hack allows us to handle exceptions through the Puzzle in IPython.
41+
# Normally when a cell is executed in an IPython InteractiveShell,
42+
# sys.excepthook is overwritten with shell.excepthook, and then restored
43+
# to sys.excepthook after the cell run finishes. Any changes we make to
44+
# sys.excepthook in here directly will thus be overwritten as soon as the
45+
# cell that defines the Puzzle finishes running.
46+
47+
# Instead, we schedule set_excepthook on a QTimer, meaning that it will
48+
# execute in the Qt loop rather than in a cell, so it can modify
49+
# sys.excepthook without risk of the changes being immediately overwritten,
50+
51+
# For bonus points, we could set _old_excepthook to shell.excepthook,
52+
# which would result in all tracebacks appearing in the Notebook rather
53+
# than the console, but I think that is not desireable.
54+
55+
# In normal Python, we could just say "sys.excepthook = self._excepthook"
56+
# but this method works for both.
57+
def set_excepthook():
58+
self._old_excepthook = sys.excepthook
59+
sys.excepthook = self._excepthook
60+
QtCore.QTimer.singleShot(0, set_excepthook)
4161

4262
@property
4363
def pieces(self):
@@ -130,7 +150,7 @@ def run_worker(self, worker):
130150
self._threadpool.start(worker)
131151

132152
def _excepthook(self, exctype, value, traceback):
133-
sys.__excepthook__(exctype, value, traceback)
153+
self._old_excepthook(exctype, value, traceback)
134154

135155
# Stop any threads that may be running
136156
self._shutdown_threads.emit()
@@ -341,6 +361,9 @@ def closeEvent(self, event):
341361
if not self.debug:
342362
for piece_name in self.pieces:
343363
self.pieces[piece_name].handle_close(event)
364+
365+
# Reinstate the original excepthook
366+
sys.excepthook = self._old_excepthook
344367
super().closeEvent(event)
345368

346369

0 commit comments

Comments
 (0)