jupyasyncclient runs code on Jupyter kernels hosted by any server speaking the standard kernels API: rustygate, jupygate, or jupyter_server. Kernel lifecycle (create, interrupt, restart, delete) is plain HTTP; messaging is one websocket per client carrying standard Jupyter message dicts with a channel key. There is no zmq and no tornado in the client process, and every send is genuinely awaited - the zmq-side subtleties (sync-send edge consumption, slow-joiner subscriptions, socket identity contracts) all live server-side.
Three classes cover the usual shapes, mirroring jupyter_client where familiarity helps:
JupyAsyncKernelClient- one kernel: lifecycle, channels, and messaging.execute,complete,inspect,history,kernel_info,wait_for_ready, and per-channelget_*_msgaccessors work like their jupyter_client namesakes; any request can await its reply directly withreply=True; and every*_requestmessage type in the protocol is callable by name, subshell requests included, so new protocol messages need no client release.JupyAsyncKernelManager- start/stop one kernel and mint clients for it.JupyAsyncMultiKernelManager- a fleet, with keyed reuse:ensure_kernel('some-key')returns the live kernel registered under that key or starts a fresh one.
The core notebook builds the client bottom-up with every method demonstrated against a live server; the managers are thin HTTP wrappers and live in plain modules.
Two sibling pages cover the rest of a gateway’s surface: term attaches JupyAsyncTerminalClient to gateway-hosted terminals, and files builds JupyAsyncFilesClient and JupyAsyncCellsClient over the files and cells APIs, including apply_ops for keeping a local view current from a kernel’s change broadcasts.
pip install jupyasyncclientPlus a server to talk to. The examples here use rustygate serving ipymini kernels; a stock jupyter_server works identically (the test suite runs against one).
import asyncio
from rustygate.tools import start_gatewayg = start_gateway()
gTrue
start_new_server_kernel gives a running kernel and a ready client in one call:
km, kc = await start_new_server_kernel(g.url)
rep = await kc.execute("print('hello'); 6*7", reply=True, timeout=30)
rep['content']['status']'ok'
Outputs arrive on the iopub queue, like jupyter_client:
m = await kc.get_iopub_msg(timeout=15)
while m['msg_type'] != 'stream': m = await kc.get_iopub_msg(timeout=15)
m['content']['text']'hello\n'
input() in the kernel becomes an input_request on the stdin queue; answer it with input, which parents the reply properly:
fut = asyncio.ensure_future(kc.execute("name = input('who? ')", reply=True, timeout=30))
prompt = await kc.get_stdin_msg(timeout=15)
kc.input('Jeremy')
(await fut)['content']['status']'ok'
Any protocol request type works by name, reply=True awaiting its reply - here JEP 91 subshells, no client support required beyond the message type:
sub = (await kc.create_subshell(reply=True, timeout=15))['content']['subshell_id']
rep = await kc.execute('40+2', reply=True, timeout=30, subshell_id=sub)
await kc.delete_subshell(sub, reply=True, timeout=15)
rep['content']['status']'ok'
The multimanager runs fleets, with keyed reuse for “the kernel for X” patterns:
mkm = JupyAsyncMultiKernelManager(g.url)
k1 = await mkm.ensure_kernel('analysis')
k2 = await mkm.ensure_kernel('analysis')
k1 == k2True
await kc.aclose()
await km.aclose()
await mkm.shutdown_all()
await mkm.aclose()Auth is a bearer token when the server requires one: pass token=... to any of the three classes and it is sent as an Authorization header on HTTP and a query param on the websocket.