Metadata-Version: 2.4
Name: chalk-remote-call-python
Version: 1.2.0
Summary: Chalk remote call Python runtime interface client
Author: Chalk AI, Inc.
Project-URL: Homepage, https://chalk.ai
Project-URL: Documentation, https://docs.chalk.ai
Project-URL: Changelog, https://docs.chalk.ai/docs/changelog
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python
Classifier: Typing :: Typed
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: <3.14,>=3.10
Description-Content-Type: text/markdown
Requires-Dist: pyarrow>=14.0.0
Provides-Extra: dev
Requires-Dist: setuptools-rust>=1.7; extra == "dev"
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: grpcio>=1.60.0; extra == "dev"
Requires-Dist: grpcio-health-checking>=1.60.0; extra == "dev"
Requires-Dist: grpcio-reflection>=1.60.0; extra == "dev"
Requires-Dist: protobuf>=4.25.0; extra == "dev"
Requires-Dist: grpcio-tools>=1.60.0; extra == "dev"

# chalk-remote-call-python

A Python runtime interface for Chalk's RemoteCallService. This package provides a gRPC server backed by a Rust implementation (tonic + PyO3) that lets you define a `handler(event, context)` function to process incoming Arrow-serialized requests.

The server receives Arrow IPC record batches over a bidirectional gRPC stream, transforms them into a Python dict, invokes your handler, and streams the results back as Arrow IPC.

## Requirements

- Python >= 3.10
- Rust toolchain (for building the native extension)
- `pyarrow >= 14.0.0`

## Usage

### 1. Write a handler

Create a Python module with a `handler` function:

```python
# my_handler.py
import pyarrow as pa
import pyarrow.compute as pc


def on_startup():
    """Optional -- runs once before the server starts accepting requests."""
    print("Loading model weights...")


def handler(event: dict[str, pa.Array], context: dict) -> pa.Array:
    """Called for each incoming request.

    Args:
        event: dict mapping column names to pyarrow.Array values.
        context: dict with request metadata

    Returns:
        A pyarrow.Array, pyarrow.RecordBatch, pyarrow.Table, list, dict, or scalar.
        The framework auto-converts the result to Arrow IPC for the response.
    """
    return pc.multiply(event["x"], event["y"])


def on_shutdown():
    """Optional -- runs once after the server stops accepting requests."""
    print("Releasing resources...")
```

### 2. Start the server

```bash
chalk-remote-call --handler my_handler.handler
```

Or via `python -m`:

```bash
python -m chalk_remote_call --handler my_handler.handler
```

### CLI options

| Flag | Env var | Default | Description |
|------|---------|---------|-------------|
| `--handler` | | *(required)* | Dotted path to handler function |
| `--port` | `CHALK_REMOTE_CALL_PORT` | `6666` | Port to listen on |
| `--host` | `CHALK_REMOTE_CALL_HOST` | `[::]` | Host to bind to |
| `--workers` | `CHALK_REMOTE_CALL_WORKERS` | `10` | Tokio runtime worker threads |
| `--on-startup` | | | Dotted path to a startup function |
| `--on-shutdown` | | | Dotted path to a shutdown function |
| `--log-level` | | `INFO` | `DEBUG`, `INFO`, `WARNING`, or `ERROR` |

### Environment variables

| Variable | Description |
|----------|-------------|
| `CHALK_INPUT_ARGS` | Comma-separated list of column names (e.g. `x,y,z`). Renames incoming RecordBatch columns by index. If unset, the original column names are used. |

### 3. Docker image

```dockerfile
FROM python:3.11-slim

WORKDIR /app

RUN pip install chalk-remote-call-python

# Copy your handler code
COPY my_handler.py /app

EXPOSE 6666

ENTRYPOINT ["chalk-remote-call"]
CMD ["--handler", "handler.handler"]
```

Build and run:

```bash
docker build -t my-chalk-handler .
docker run -p 6666:6666 -e CHALK_INPUT_ARGS="x,y" my-chalk-handler
```

### Programmatic usage

You can also start the server from Python:

```python
from chalk_remote_call import serve

def handler(event, context):
    return list(event.values())[0]

serve(handler=handler, port=8080)
```

## Local Testing

Use `grpcurl` to verify the server is running:

```bash
# Check health
grpcurl -plaintext localhost:6666 grpc.health.v1.Health/Check

# List services via reflection
grpcurl -plaintext localhost:6666 list
```

## Architecture

The server uses a Rust backend via PyO3:

- **tonic** — gRPC server with health checking and reflection
- **prost** — protobuf message handling
- **arrow-rs** — Arrow IPC validation
- **PyO3** — FFI bridge to call Python handler functions

The Rust server runs on a tokio async runtime. When a request arrives, Arrow IPC bytes are passed to Python via PyO3 (`spawn_blocking` + GIL acquisition), where the handler is invoked. Results are passed back as IPC bytes.

## Development

### Setup

```bash
cd chalk-remote-call-python
uv venv --python 3.11
uv pip install -e ".[dev]"
```

### Running tests

```bash
pytest tests/ -v
```

### Rust code

Rust source lives in `chalk-remote-call-rs/`:

To check the Rust code independently:

```bash
PYO3_PYTHON=python3 cargo check --manifest-path chalk-remote-call-rs/chalk-remote-call-server/Cargo.toml
```
