Skip to content

Commit

Permalink
inputhook_qt4: handle KeyboardInterrupt in a way compatible with 'rea…
Browse files Browse the repository at this point in the history
…dline'.

While the previous code works fine on Windows, on Linux with
'readline' the situation is different: once we disable the Qt4 event
loop, we go back waiting in the select() inside readline.c's
readline_until_enter_or_signal() function. When that select() is
interrupted, the PyOS_InputHook is executed if present and the pending
KeyboardInterrupt is delivered as soon as bytecode execution starts,
even before entering the `try:` clause! As at that point we're in a
ctypes callback, this will lead to an internal error. The only
solution is therefore to disable the PyOS_InputHook temporarily.
  • Loading branch information
cboos committed Oct 9, 2011
1 parent 6ab38c6 commit fa66348
Showing 1 changed file with 11 additions and 12 deletions.
23 changes: 11 additions & 12 deletions IPython/lib/inputhook.py
Expand Up @@ -208,23 +208,16 @@ def enable_qt4(self, app=None):
# #481).

# Note that we can't let KeyboardInterrupt escape from that
# hook, (no exception can't be raised from within a ctypes
# python callback). We need to make a compromise: a trapped
# KeyboardInterrupt will prevent the input hook to re-enter
# the exec loop, until we start over with a new prompt line.
# This means one needs a double CTRL+C to get back to the
# prompt.
# hook, as no exception can be raised from within a ctypes
# python callback. We need to make a compromise: a trapped
# KeyboardInterrupt will temporarily disable the input hook
# until we start over with a new prompt line with a second
# CTRL+C.

got_kbdint = [False]

def preprompthook_qt4(self):
got_kbdint[0] = False
ipapi.get().set_hook('pre_prompt_hook', preprompthook_qt4)

def inputhook_qt4():
try:
if got_kbdint[0]:
return 0
app.processEvents(QtCore.QEventLoop.AllEvents, 300)
if not stdin_ready():
timer = QtCore.QTimer()
Expand All @@ -235,11 +228,17 @@ def inputhook_qt4():
timer.stop()
except KeyboardInterrupt:
got_kbdint[0] = True
self.clear_inputhook()
print("\n(event loop interrupted - "
"hit CTRL+C again to clear the prompt)")
return 0
self.set_inputhook(inputhook_qt4)

def preprompthook_qt4(ishell):
if got_kbdint[0]:
self.set_inputhook(inputhook_qt4)
ipapi.get().set_hook('pre_prompt_hook', preprompthook_qt4)

self._current_gui = GUI_QT4
app._in_event_loop = True
self._apps[GUI_QT4] = app
Expand Down

0 comments on commit fa66348

Please sign in to comment.