Skip to main content

Nodus Python SDK

Run a training job on rented GPUs from Python. Nodus places the work on the cheapest capacity that fits, checkpoints it, and resumes it if the machine is taken back — so a fine-tune that would have died at hour six finishes.

import nodus

with nodus.Client() as client:
    wl = client.run(command=["python", "train.py"], budget=20)
    print(client.wait(wl.id).status)

Install

pip install nodus_compute

The distribution is nodus_compute; the import is nodus.

Point it at your account

Two settings. Sign in at https://nodus.run/console/, create an API key — it is shown once — and the console's quickstart comes with both already filled in.

export NODUS_API_KEY=nk_live_…
export NODUS_BASE_URL=https://…

Or pass them directly: nodus.Client(api_key=…, base_url=…).

There is no built-in address. With neither setting the client raises ConfigurationError before it opens a socket, naming what is missing — it does not dial a guess and hand you a name-lookup error.

Running work

run() takes a flat brief and returns a Workload:

import nodus

with nodus.Client() as client:
    wl = client.run(
        image="python:3.11-slim",
        command=["python", "train.py", "--epochs", "3"],
        peak_memory_gb=24,          # picks capacity that fits
        expected_runtime_hours=6,   # informs the estimate
        budget=40,                  # a ceiling, not a reservation
    )

    done = client.wait(wl.id)       # polls until the run is over
    print(done.status, done.cost_now_usd)

Nothing is strictly required. Omit image and the default python:3.11-slim fills in; omit command and the image's own entrypoint runs. Everything else narrows the search or bounds the cost; omit budget and the run is uncapped — the SDK warns rather than inventing a ceiling on your money.

Your image must be able to fetch a small binary — it needs curl, wget, or python3 on the PATH. Most ML images have one. A bare ubuntu image has none of them, and a machine that cannot fetch the runner is a machine you are billed for while it does nothing.

Waiting

wait() polls until the workload is terminal and has no deadline of its own. An 18-hour run is normal, and a client that gave up on one would not stop it — the work would carry on and keep billing while your program believed it had failed. A transient network failure does not end the wait either; only a permanent one (a revoked key, an unknown workload) is raised.

Pass timeout_seconds= if you want a bound. It ends the waiting, not the run: APITimeoutError is raised, the workload continues, and .cancel() is what stops it.

Watching it

for event in client.stream_events(wl.id):
    print(event.type, event.payload)

print(client.logs(wl.id))           # the job's own stdout and stderr
print(wl.refresh().cost_now_usd)    # charged plus what is accruing right now

logs() is not a live tail. The log is a committed artifact, so it lags the process by a checkpoint and raises NotFoundError until the first checkpoint carries one — for live progress, watch the events.

Async

AsyncClient mirrors Client method for method:

async with nodus.AsyncClient() as client:
    wl = await client.run(command=["python", "train.py"])
    done = await client.wait(wl.id)

Errors

Every failure is a subclass of NodusError, so one except catches the lot. The column that matters when writing a handler is whether the condition clears on its own — the SDK already retries the ones that do, and never retries the ones that do not.

Raised When Clears on its own?
ConfigurationError a setting is missing, before any request never
AuthenticationError the key is wrong or revoked never
SignatureError a signed request was rejected — the key is fine, the signature is not never
ValidationError the brief was rejected, with the reason never
IdempotencyConflictError an Idempotency-Key was reused with a different payload never
NotFoundError no such workload never
BudgetExceededError the run would pass your account's spend cap only if you lower the ask or raise the cap
RateLimitError too many requests; honours Retry-After yes, with time
CapacityUnavailableError nothing in the market fits the brief yes
APIConnectionError / APITimeoutError the network, not the API yes
APIError any other 4xx/5xx for 5xx, usually

Command line

Everything after a bare -- is your program's own command line, passed through untouched:

nodus run --budget 20 -- python train.py
nodus get wl_…
nodus logs wl_…

Licence

Apache-2.0. See LICENSE.

Release files for nodus-compute 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nodus-compute 0.1.1
File Size Uploaded
nodus_compute-0.1.1.tar.gz 65.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nodus-compute 0.1.1
File Interpreter ABI Platform
nodus_compute-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 103.9 kB

Release files / nodus_compute-0.1.1.tar.gz

Download URL nodus_compute-0.1.1.tar.gz
Size 65.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9c9c54a56e959762b97795e23ac1e184f05cb95e63dedf5b6da00d003a1efaab
BLAKE2b-256 checksum
How to use checksums
934a664283284931ef75333e3db538f59c662514b1dbeee5a1135f8e38bff9dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release files / nodus_compute-0.1.1-py3-none-any.whl

Download URL nodus_compute-0.1.1-py3-none-any.whl
Size 38.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0eecd6e89edab07168d2a5071686b34fca7eced766daea0a2034ece7d6f01005
BLAKE2b-256 checksum
How to use checksums
2d8fc74f2da19cd6b5274c37905294d2d53735bf90f9f02f49a67e863e86045e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page