Skip to main content

3torus — Python SDK

Typed Python client for the 3Torus GPU compute marketplace API. The Python sibling of the 3torus CLI: the same gRPC core-services surface, exposed as a typed client with Pydantic models.

Status (CLAUDE.md Rule 39): first leg, Done@L1 — typed client + tests against an in-process fake server. Live-API use (L2) needs the public API gateway active or a kubectl port-forward; the gateway activation is operator-gated (m3-plan Phase C — M3-GRPC-GATEWAY-REST). Several RPCs are contract-only / Unimplemented server-side until each handler ships under M3-CORE-SERVICES-SERVER-IMPL.

Install

pip install 3torus          # dist name
import threetorus           # import name

Quickstart — submit a GPU job in 5 lines

from threetorus import Client

with Client("api.dev.3torus.com:443", api_key="3t_...", secure=True) as c:
    job = c.jobs.submit(image="nvidia/cuda-samples:vectoradd", gpu_count=1)
    print(job.id, job.status.name)          # gpu-vectoradd-019e943b SUBMITTED
    result = c.jobs.get(job.id)             # poll until terminal
    print(result.status.name, result.result and result.result.output_uri)

The API key rides on every RPC as an authorization: Bearer <key> gRPC metadata header — it is never logged, never placed in the address, and never echoed in an exception (CLAUDE.md Rule 10). Prefer loading it from an environment variable or secret store; never hard-code it.

This is the seed for the GitBook SDK Quickstart (M3-GITBOOK-SDK-QUICKSTART) — keep the 5-line example in sync.

Verb surface

The client mirrors the CLI's verb groups one-to-one. Each sub-client fronts one gRPC core service:

Sub-client Service Methods
client.clusters user.v1 ComputeService (your own clusters) list, get
client.jobs JobsService submit, get, list, cancel
client.billing BillingService usage, quota, invoices, balance
client.providers ProvidersService list, get, gpu_skus
client.health HealthService check
client.auth AuthService (validate), user.v1 IdentityService (whoami → Identity) validate, whoami
clusters, page = c.clusters.list(phase=ClusterPhase.READY)   # your tenant only
usage = c.billing.usage("client-acme")
skus, _ = c.providers.gpu_skus(tier="datacenter")
status = c.health.check()
who = c.auth.validate("3t_...")

Typed models

Responses are Pydantic models with native Python types — datetime for timestamps, Decimal for money, IntEnum for enums — instead of raw protobuf accessors:

from threetorus import models as m

job: m.Job = c.jobs.get("job-id")
job.status            # m.JobStatus.COMPLETED  (IntEnum, .name == "COMPLETED")
job.completed_at      # datetime | None  (UTC; None when unset)
usage.estimated_cost  # m.Money(amount=Decimal("4.20"), currency="USD")

Errors

Every gRPC failure is mapped to a typed exception carrying the original grpc.StatusCode + the server's message verbatim:

from threetorus import NotFoundError, UnimplementedError, UnavailableError

try:
    c.clusters.get("does-not-exist")
except NotFoundError as e:
    print(e.code, e.message)        # StatusCode.NOT_FOUND ...

UNAVAILABLE / DEADLINE_EXCEEDED are retried automatically with capped exponential backoff before surfacing; permanent codes are never retried. Override the policy with Client(..., retry=RetryPolicy(max_attempts=5)).

Roadmap (later legs)

  • L2 live-API verification against the public gateway / port-forward.
  • PyPI publish of the 3torus distribution — automated by release-sdk.yml (see Releasing to PyPI below); the first published version waits on the operator's trusted-publisher registration.
  • Async client (grpcio aio) for high-concurrency callers.

See the platform backlog row M3-PYTHON-SDK. Sibling rows: M3-CLI-3TORUS (the Go CLI), M3-GITBOOK-SDK-QUICKSTART (docs).

Releasing to PyPI

Releases are tag-driven and publish through PyPI trusted publishing (GitHub OIDC → short-lived upload token). There is no long-lived PyPI token anywhere — not in a repo secret, not in 1Password. The workflow is .github/workflows/release-sdk.yml (M4-RELEASE-AUTOMATION-SDK-CLI batch 1).

  1. Bump [project].version in pyproject.toml on a branch, merge to main.

  2. Tag that commit on main and push the tag:

    git tag v0.1.1            # MUST equal pyproject.toml [project].version
    git push origin v0.1.1
    
  3. The workflow asserts the tag equals the declared version (scripts/sdk-version-from-tag.sh — a mismatch fails the run, nothing is stamped), asserts the tagged commit is reachable from main, builds the wheel with the canonical gen/core stubs inside, runs twine check, and publishes the wheel to https://pypi.org/project/3torus/.

  4. Verify from a clean environment (the row's L2 probe):

    pip download 3torus==0.1.1 --no-deps -d ./dl
    

Dry run (build + twine check + version assert, no publish): gh workflow run release-sdk.yml --ref main — dry_run defaults to true.

Before the first release the operator registers the workflow as a trusted publisher on PyPI (operator-actions-register row 29): project 3torus, owner alexperritaz, repository 3-torus, workflow release-sdk.yml, environment pypi. Until then the publish step fails with PyPI's "trusted publishing not configured" error — that is the expected pre-registration state, not a workflow defect.

Wheel only. The sdist hatchling emits omits gen/core (the force-include is wheel-scoped), so it cannot be built into a working install; publishing it would be a lie on the index. Tracked as M4-SDK-SDIST-OMITS-GEN-CORE.

Changelog

Pre-1.0: a minor bump may break the API; a patch bump never does. The version lives in TWO places that must match — pyproject.toml [project].version and threetorus.__version__ (the latter rides every RPC in the x-3torus-client header) — and the release tag must equal them (scripts/sdk-version-from-tag.sh).

0.3.0 (unreleased)

Breaking (M4-CORE-V1-COMPUTE-TENANT-SCOPE — client.clusters now speaks the tenant-scoped torus.user.v1.ComputeService; core.v1 Compute is no longer publicly routed):

  • clusters.list() returns only YOUR tenant's clusters; clusters.get() of another tenant's cluster raises NotFoundError.
  • clusters.list(role=…) removed — passing it raises TypeError.
  • clusters.list_nodes() and clusters.capacity() removed (never implemented server-side; no user-plane equivalent). models.Node, models.Capacity, models.ClusterRole removed with them.
  • models.Cluster drops role, gains gpu_model.

Fixed: jobs.list(page=…/page_size=…) and billing.invoices(page=…/ page_size=…) raised TypeError before sending anything — they built a core.v1 PageRequest for a user.v1 request.

0.2.0 (never tagged)

Jobs, billing and auth.whoami() moved to torus.user.v1 (KKKK.290 / decision #295). Superseded by 0.3.0 before any tag was cut.

Development

pip install -e ".[dev]"     # from sdk/python/
ruff check src tests
pytest

The generated protobuf stubs are not vendored here — the wheel force-includes the repo's canonical gen/core tree (produced by buf generate) as the core package, so the SDK never drifts from the proto contracts (scripts/check-proto-codegen-sync.sh).

Metadata

Release files for 3torus 0.3.0

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

Built distribution (wheel)

Table of built distributions (wheels) for 3torus 0.3.0
File Interpreter ABI Platform
3torus-0.3.0-py3-none-any.whl Python 3 none any Details

Release files / 3torus-0.3.0-py3-none-any.whl

Download URL 3torus-0.3.0-py3-none-any.whl
Size 299.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f742337f5ab5d78f3c4efd30506be5c6b1546316957eb190afcd63ef1a13e516
BLAKE2b-256 checksum
How to use checksums
6f0db5cc749de5558e2e68e95a118a43beee6400e8151f9d2baf4cf42cc0d5c1
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 Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.1

1 release file

This release

0.3.0 This release

1 release file

0.1.3

1 release file

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