# Python SDK

> Install the nodus-compute package, sign in, and run your first Function, Sandbox and Job from Python.

Source: https://nodus-platform-site.pages.dev/docs/guides/python/
Build revision: 211ad9f836655b1c3a2668c4693e442471f28614

The `nodus-compute` package (import `nodus`) runs Python functions, Sandboxes, Jobs and Workspaces on Nodus, and calls models through the inference data plane. It supports Python 3.10 to 3.13.

## Install and sign in

Terminal window

```console
pip install nodus-compute
nodus login
```

`nodus login` opens the console in your browser and stores a key for each org you pick in `~/.nodus/config`, which the SDK reads. On a server or in CI, create an API key in the console and set it instead:

Terminal window

```console
export NODUS_API_KEY=nodus_sk_live_...
export NODUS_PROJECT=default        # optional; the project to use
```

The SDK resolves credentials in this order: arguments to `nodus.Client(...)`, the variables `NODUS_API_KEY`, `NODUS_API_URL`, `NODUS_ORG`, `NODUS_PROJECT`, `NODUS_CONTEXT` and `NODUS_CONFIG`, then the current context of `~/.nodus/config`.

## Your first Function

examples/python/quickstart/app.py

```python
"""Quickstart: one Function called three ways.

Run it with `nodus run examples/python/quickstart/app.py --n 10`.
"""

import nodus

app = nodus.App("quickstart")


@app.function(cpu=1, memory="1Gi", max_cost=1)
def square(x: int) -> int:
    return x * x


@app.local_entrypoint()
def main(n: int = 10) -> None:
    print("remote:", square.remote(7))  # one call; blocks for the result
    call = square.spawn(8)  # start without waiting
    print("spawned:", call.get(timeout=600))
    print("map:", list(square.map(range(n))))  # one call per input, results in input order
```

Terminal window

```console
nodus run examples/python/quickstart/app.py --n 10
```

`nodus run` creates an ephemeral App, runs `main` on your machine and deletes the App when `main` returns. Each `.remote()` call runs on Nodus and returns its result. `nodus deploy` keeps the App so other programs can call it with `nodus.Function.from_name("quickstart", "square")`.

## Blocking and asyncio

Every call blocks by default. Each one also has an `.aio` form for asyncio code:

```python
async def main():
    async with app.run.aio():
        print(await square.remote.aio(7))
        async for y in square.map.aio(range(10)):
            print(y)
```

## Errors

Every error is a `nodus.errors.NodusError`. API errors have one class per code (`NotFound`, `Invalid`, `InsufficientCredits`, `QuotaExceeded`, …) and carry `message`, `fix`, `docs` and `request_id`. An exception raised inside a Function is raised again on your side with its own type when that type can be imported, chained from a `nodus.errors.RemoteError` that holds the remote traceback.

```python
from nodus import errors

try:
    train.remote(3e-4)
except errors.InsufficientCredits as e:
    print(e.needed_usd, e.available_usd, e.fix)
```

## Guides

* [Functions and classes](https://nodus-platform-site.pages.dev/docs/guides/python/functions/): `@app.function`, `.remote`, `.map`, `@app.cls`, deploys
* [Sandboxes](https://nodus-platform-site.pages.dev/docs/guides/python/sandboxes/): exec, files, tunnels, snapshots
* [Jobs](https://nodus-platform-site.pages.dev/docs/guides/python/jobs/): batch containers, outputs, multi-node gangs
* [Images, Volumes and Secrets](https://nodus-platform-site.pages.dev/docs/guides/python/storage/)
* [Workspaces](https://nodus-platform-site.pages.dev/docs/guides/python/workspaces/): development machines
* [Agents](https://nodus-platform-site.pages.dev/docs/guides/python/agents/): durable runs, fan-out and groups
* [Inference](https://nodus-platform-site.pages.dev/docs/guides/python/inference/): the OpenAI and Anthropic clients
* [The resource API](https://nodus-platform-site.pages.dev/docs/guides/python/api/): `nodus.api` for any kind
