Skip to content

Commit 05aa0e8

Browse files
authored
Merge pull request #741 from afshin/interrupt
Add Support for Message Based Interrupt
2 parents 2767f3e + 679c9a3 commit 05aa0e8

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

ipykernel/kernelbase.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import itertools
1111
import logging
1212
import inspect
13+
import os
1314
from signal import signal, default_int_handler, SIGINT
1415
import sys
1516
import time
@@ -198,7 +199,7 @@ def _parent_header(self):
198199
'inspect_request', 'history_request',
199200
'comm_info_request', 'kernel_info_request',
200201
'connect_request', 'shutdown_request',
201-
'is_complete_request',
202+
'is_complete_request', 'interrupt_request',
202203
# deprecated:
203204
'apply_request',
204205
]
@@ -780,6 +781,30 @@ async def comm_info_request(self, stream, ident, parent):
780781
reply_content, parent, ident)
781782
self.log.debug("%s", msg)
782783

784+
async def interrupt_request(self, stream, ident, parent):
785+
pid = os.getpid()
786+
pgid = os.getpgid(pid)
787+
788+
if os.name == "nt":
789+
self.log.error("Interrupt message not supported on Windows")
790+
791+
else:
792+
# Prefer process-group over process
793+
if pgid and hasattr(os, "killpg"):
794+
try:
795+
os.killpg(pgid, SIGINT)
796+
return
797+
except OSError:
798+
pass
799+
try:
800+
os.kill(pid, SIGINT)
801+
except OSError:
802+
pass
803+
804+
content = parent['content']
805+
self.session.send(stream, 'interrupt_reply', content, parent, ident=ident)
806+
return
807+
783808
async def shutdown_request(self, stream, ident, parent):
784809
content = self.do_shutdown(parent['content']['restart'])
785810
if inspect.isawaitable(content):

ipykernel/tests/test_kernel.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,26 @@ def test_interrupt_during_input():
391391
validate_message(reply, 'execute_reply', msg_id)
392392

393393

394+
@pytest.mark.skipif(
395+
os.name == "nt",
396+
reason="Message based interrupt not supported on Windows"
397+
)
398+
def test_interrupt_with_message():
399+
"""
400+
401+
"""
402+
with new_kernel() as kc:
403+
km = kc.parent
404+
km.kernel_spec.interrupt_mode = "message"
405+
msg_id = kc.execute("input()")
406+
time.sleep(1) # Make sure it's actually waiting for input.
407+
km.interrupt_kernel()
408+
from .test_message_spec import validate_message
409+
# If we failed to interrupt interrupt, this will timeout:
410+
reply = get_reply(kc, msg_id, TIMEOUT)
411+
validate_message(reply, 'execute_reply', msg_id)
412+
413+
394414
@pytest.mark.skipif(
395415
version.parse(IPython.__version__) < version.parse("7.14.0"),
396416
reason="Need new IPython"

0 commit comments

Comments
 (0)