Metadata-Version: 2.4
Name: jupyasyncclient
Version: 0.2.18
Summary: Async kernel client for Jupyter Server via HTTP/WebSocket
Author: Jeremy Howard
License: Apache-2
Project-URL: Repository, https://github.com/AnswerDotAI/jupyasyncclient
Project-URL: Documentation, https://AnswerDotAI.github.io/jupyasyncclient/
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: jupywire>=0.1.12
Requires-Dist: fasttransport>=0.0.2
Requires-Dist: fastcore>=2.1.17
Requires-Dist: websockets>=13
Requires-Dist: fastspec>=0.2.4
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: jupyter_server>=2; extra == "dev"
Requires-Dist: ipykernel; extra == "dev"
Requires-Dist: pytest-timeout; extra == "dev"
Requires-Dist: rustygate>=0.1.17; extra == "dev"
Requires-Dist: ipymini>=0.1.17; extra == "dev"
Requires-Dist: ipyfuncs>=0.0.1; extra == "dev"

# jupyasyncclient


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

`jupyasyncclient` is an async Python client for running code on Jupyter kernels. It connects to servers that implement the standard kernels API, including [rustygate](https://github.com/AnswerDotAI/rustygate), jupygate, and jupyter_server.

Kernel creation, interruption, restart, and deletion use HTTP. Each client exchanges messages over one websocket. Sends await the websocket transport. The client does not depend on zmq or tornado.

Three classes provide jupyter_client-style interfaces:

- [`JupyAsyncKernelClient`](https://AnswerDotAI.github.io/jupyasyncclient/core.html#jupyasynckernelclient) manages one kernel’s lifecycle, channels, and messages.
- `JupyAsyncKernelManager` starts and stops one kernel and creates clients for it.
- `JupyAsyncMultiKernelManager` manages multiple kernels. `ensure_kernel('some-key')` returns the live kernel registered under that key or starts one.

The [core notebook](00_core.ipynb) builds the client bottom-up and demonstrates every method against a live server. The managers are HTTP wrappers in plain modules. Two other notebooks cover gateway APIs:

- [term](01_term.ipynb) demonstrates [`JupyAsyncTerminalClient`](https://AnswerDotAI.github.io/jupyasyncclient/term.html#jupyasyncterminalclient) for gateway-hosted terminals.
- [files](02_files.ipynb) builds [`JupyAsyncFilesClient`](https://AnswerDotAI.github.io/jupyasyncclient/files.html#jupyasyncfilesclient) and [`JupyAsyncCellsClient`](https://AnswerDotAI.github.io/jupyasyncclient/files.html#jupyasynccellsclient) over the files and cells APIs. It includes [`apply_ops`](https://AnswerDotAI.github.io/jupyasyncclient/files.html#apply_ops) for updating a local view from a kernel’s change broadcasts.

[`JupyAsyncCellsClient.view`](https://AnswerDotAI.github.io/jupyasyncclient/files.html#jupyasynccellsclient.view) returns selected cells with the current notebook path and requested metadata. `cells` returns the selected cell list. Both accept a filename or a kernel binding through the client constructor.

## Install

``` sh
pip install jupyasyncclient
```

You also need a kernel server. These examples use rustygate serving [ipymini](https://github.com/AnswerDotAI/ipymini) kernels. The test suite also runs against a stock jupyter_server.

## Use

The client’s `execute`, `complete`, `inspect`, `history`, `kernel_info`, and `wait_for_ready` methods follow their jupyter_client namesakes. Choose how to receive execution results:

- `execute` sends without waiting for a reply.
- `reply` awaits one `execute_reply`.
- `run` collects every message caused by an execution.

Every inbound message also reaches the `on_jmsg` callback once, in receive order, after request routing. The callback can be synchronous or asynchronous. The reader awaits it before taking the next message. Do not await replies on the same websocket from the callback. `JmsgQueues` provides queues for applications that need to pull the same messages instead.

Every protocol `*_request` type is callable by name and returns an awaitable for its reply. This includes subshell requests. New protocol messages do not require a client release.

Messages are standard Jupyter dictionaries with a `channel` key. The server handles zmq-specific behaviour, including sync-send edge consumption, slow-joiner subscriptions, and socket identity.

``` python
import asyncio
from rustygate.tools import start_gateway
```

``` python
g = start_gateway()
g
```

    <Gateway http://127.0.0.1:60487 pid=47781 up>

`start_new_server_kernel` starts a kernel and returns its manager and a ready client. This example uses a single `jmsg` queue for iopub and stdin messages:

``` python
km, kc = await start_new_server_kernel(g.url)
qs = JmsgQueues(kc, queues=('jmsg',), merge=dict(iopub='jmsg', stdin='jmsg'))
rep = await kc.reply("print('hello'); 6*7", timeout=30)
rep['content']['status']
```

    'ok'

Kernel output arrives on the iopub channel. Read the `stream` message from the queue:

``` python
m = await qs.jmsg_for('stream', timeout=15)
m['content']['text']
```

    'hello\n'

Calling `input()` in the kernel produces an `input_request` on the stdin channel. Answer with the client’s `input` method. It sets the reply’s parent to the request:

``` python
fut = asyncio.ensure_future(kc.reply("name = input('who? ')", timeout=30))
prompt = await qs.jmsg_for('input_request', timeout=15)
kc.input('Jeremy')
(await fut)['content']['status']
```

    'ok'

Call protocol requests by name and await their replies. This example creates and deletes a JEP 91 subshell:

``` python
sub = (await kc.create_subshell(timeout=15))['content']['subshell_id']
rep = await kc.reply('40+2', timeout=30, subshell_id=sub)
await kc.delete_subshell(sub, timeout=15)
rep['content']['status']
```

    'ok'

Use the multimanager to keep a kernel for each named task. Repeated calls to `ensure_kernel` with the same key reuse its live kernel:

``` python
mkm = JupyAsyncMultiKernelManager(g.url)
k1 = await mkm.ensure_kernel('analysis')
k2 = await mkm.ensure_kernel('analysis')
k1 == k2
```

    True

``` python
await kc.aclose()
await km.shutdown_kernel()
await mkm.shutdown_all()
```

Pass `token=...` to any of the three classes when the server requires a bearer token. HTTP requests send it in the `Authorization` header. Websocket connections send it as a query parameter.
