Skip to content

Commit b51a3b5

Browse files
authored
Allow interrupt during restart of pending kernels (#898)
1 parent 4dbac9e commit b51a3b5

File tree

4 files changed

+22
-8
lines changed

4 files changed

+22
-8
lines changed

jupyter_client/consoleapp.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
# Aliases and Flags
3333
# -----------------------------------------------------------------------------
3434

35-
flags = {}
35+
flags: dict = {}
3636
flags.update(base_flags)
3737
# the flags that are specific to the frontend
3838
# these must be scrubbed before being passed to the kernel,
3939
# or it will raise an error on unrecognized flags
40-
app_flags = {
40+
app_flags: dict = {
4141
"existing": (
4242
{"JupyterConsoleApp": {"existing": "kernel*.json"}},
4343
"Connect to an existing kernel. If no argument specified, guess most recent",
@@ -61,11 +61,11 @@
6161
)
6262
flags.update(app_flags)
6363

64-
aliases = {}
64+
aliases: dict = {}
6565
aliases.update(base_aliases)
6666

6767
# also scrub aliases from the frontend
68-
app_aliases = {
68+
app_aliases: dict = {
6969
"ip": "JupyterConsoleApp.ip",
7070
"transport": "JupyterConsoleApp.transport",
7171
"hb": "JupyterConsoleApp.hb_port",

jupyter_client/kernelspecapp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ class KernelSpecApp(Application):
301301
}
302302
)
303303

304-
aliases: t.Dict[str, object] = {}
305-
flags: t.Dict[str, object] = {}
304+
aliases: t.Dict[str, object] = {} # type:ignore[assignment]
305+
flags: t.Dict[str, object] = {} # type:ignore[assignment]
306306

307307
def start(self):
308308
if self.subapp is None:

jupyter_client/manager.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,18 @@ async def _async_interrupt_kernel(self) -> None:
594594
Unlike ``signal_kernel``, this operation is well supported on all
595595
platforms.
596596
"""
597+
if not self.has_kernel:
598+
if self._ready is not None:
599+
if isinstance(self._ready, CFuture):
600+
ready = asyncio.ensure_future(self._ready) # type:ignore
601+
else:
602+
ready = self._ready
603+
# Wait for a shutdown if one is in progress.
604+
if self.shutting_down:
605+
await ready
606+
# Wait for a startup.
607+
await ready
608+
597609
if self.has_kernel:
598610
assert self.kernel_spec is not None
599611
interrupt_mode = self.kernel_spec.interrupt_mode

tests/test_multikernelmanager.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,12 @@ async def _run_lifecycle(km, test_kid=None):
311311
assert kid in km
312312
assert kid in km.list_kernel_ids()
313313
assert len(km) == 1, f"{len(km)} != {1}"
314-
await km.restart_kernel(kid, now=True)
314+
# Ensure we can interrupt during a restart.
315+
fut = km.restart_kernel(kid, now=True)
316+
await km.interrupt_kernel(kid)
315317
assert await km.is_alive(kid)
318+
await fut
316319
assert kid in km.list_kernel_ids()
317-
await km.interrupt_kernel(kid)
318320
k = km.get_kernel(kid)
319321
assert isinstance(k, AsyncKernelManager)
320322
await km.shutdown_kernel(kid, now=True)

0 commit comments

Comments
 (0)