Skip to content

Python SDK

View Markdown

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.

Terminal window
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
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.

examples/python/quickstart/app.py
"""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
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").

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

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)

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.

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