Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow interrupt during restart of pending kernels #898

Merged
merged 1 commit into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions jupyter_client/consoleapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
# Aliases and Flags
# -----------------------------------------------------------------------------

flags = {}
flags: dict = {}
flags.update(base_flags)
# the flags that are specific to the frontend
# these must be scrubbed before being passed to the kernel,
# or it will raise an error on unrecognized flags
app_flags = {
app_flags: dict = {
"existing": (
{"JupyterConsoleApp": {"existing": "kernel*.json"}},
"Connect to an existing kernel. If no argument specified, guess most recent",
Expand All @@ -61,11 +61,11 @@
)
flags.update(app_flags)

aliases = {}
aliases: dict = {}
aliases.update(base_aliases)

# also scrub aliases from the frontend
app_aliases = {
app_aliases: dict = {
"ip": "JupyterConsoleApp.ip",
"transport": "JupyterConsoleApp.transport",
"hb": "JupyterConsoleApp.hb_port",
Expand Down
4 changes: 2 additions & 2 deletions jupyter_client/kernelspecapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ class KernelSpecApp(Application):
}
)

aliases: t.Dict[str, object] = {}
flags: t.Dict[str, object] = {}
aliases: t.Dict[str, object] = {} # type:ignore[assignment]
flags: t.Dict[str, object] = {} # type:ignore[assignment]

def start(self):
if self.subapp is None:
Expand Down
12 changes: 12 additions & 0 deletions jupyter_client/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,18 @@ async def _async_interrupt_kernel(self) -> None:
Unlike ``signal_kernel``, this operation is well supported on all
platforms.
"""
if not self.has_kernel:
if self._ready is not None:
if isinstance(self._ready, CFuture):
ready = asyncio.ensure_future(self._ready) # type:ignore
else:
ready = self._ready
# Wait for a shutdown if one is in progress.
if self.shutting_down:
await ready
# Wait for a startup.
await ready

if self.has_kernel:
assert self.kernel_spec is not None
interrupt_mode = self.kernel_spec.interrupt_mode
Expand Down
6 changes: 4 additions & 2 deletions tests/test_multikernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,12 @@ async def _run_lifecycle(km, test_kid=None):
assert kid in km
assert kid in km.list_kernel_ids()
assert len(km) == 1, f"{len(km)} != {1}"
await km.restart_kernel(kid, now=True)
# Ensure we can interrupt during a restart.
fut = km.restart_kernel(kid, now=True)
await km.interrupt_kernel(kid)
assert await km.is_alive(kid)
await fut
assert kid in km.list_kernel_ids()
await km.interrupt_kernel(kid)
k = km.get_kernel(kid)
assert isinstance(k, AsyncKernelManager)
await km.shutdown_kernel(kid, now=True)
Expand Down