Skip to main content

thrustlab — official Python SDK for the ThrustLab API

PyPI Python License

The official Python client for ThrustLab — electric-UAV powertrain simulation as an API.

Install

pip install thrustlab

Requires Python 3.10+.

Quickstart

from thrustlab import Client

client = Client()  # reads $THRUSTLAB_API_KEY (never hard-code the key)

# Create a project
project = client.projects.create(name="my project")

# Run a single-point simulation and wait for the result.
# A rotor group carries the motor + propeller + throttle (0–100); the battery
# and flight condition are top-level. Resolve component IDs from the catalog
# (client.components.find(name=...)) or paste them directly.
sim = client.simulations.create(
    project_id=project["id"],
    battery_component_id="comp_batt_xxx",
    airspeed_m_s=0.0,
    density_kg_m3=1.225,
    battery_charge_pct=100,
    rotor_groups=[
        {
            "label": "main",
            "count": 4,
            "motor_component_id": "comp_motor_xxx",
            "propeller_component_id": "comp_prop_xxx",
            "throttle_pct": 70,
        }
    ],
)
result = client.simulations.wait(sim["id"], timeout=300)

# Canonical snake_case result: per-rotor group under "1"/"2"/…, roll-ups
# under "All" (a sibling `display_labels` map carries the human labels).
print(result["result"]["1"]["thrust_n"], result["result"]["All"]["total_thrust_n"])

Runnable end-to-end examples for every simulation type live in examples/: simulations/run_sync.py, sweeps/run_and_poll.py, and dynamic/run_and_poll.py.

FMU export and SITL

Export a completed simulation as an FMI 3.0 co-simulation FMU:

job_id = client.fmu.export(sim_id)["id"]
client.fmu.wait(job_id)
client.fmu.download(job_id, "powertrain.fmu")

The FMU exposes per-rotor inputs and outputs, battery and thermal state, and a validity envelope; it runs in any FMI 3.0 co-simulation host and is verified in Simulink.

thrustlab-sitl, installed with the SDK, flies the FMU in ArduPilot SITL or Betaflight SITL (--target betaflight). See thrustlab/sitl/README.md for the full documentation.

thrustlab-sitl --fmu powertrain.fmu --vehicle quad_x.yaml --target betaflight

See examples/fmu/ for bundled ready-to-fly FMUs with quadcopter, Y6 coax, and tilt-tricopter missions, an endurance study, and replay rendering.

Why the SDK (and not urllib / wget)?

The SDK gives you automatic retries with backoff, idempotency keys, cursor pagination, polling helpers, webhook signature verification, and typed errors. It is built on httpx and sends its own thrustlab-python/<version> User-Agent.

If you hand-roll a client anyway, use an HTTP library with a descriptive User-Agent (httpx, requests, or curl). ThrustLab's edge protection screens non-browser User-Agents such as stdlib Python-urllib/* and wget: API paths under /v1/ are exempt from the screening, but every other route blocks these at the edge with an opaque error 1010 page — the request never reaches ThrustLab, so no JSON error envelope is possible there.

Configuration

Setting Constructor arg Env var Default
API key api_key= THRUSTLAB_API_KEY (required)
Base URL base_url= THRUSTLAB_BASE_URL https://thrustlab.com
Timeout timeout= — 30 (seconds)
Max retries max_retries= — 3

Resources

Every /v1/ route family is exposed as an attribute on the client:

client.users
client.projects
client.simulations
client.sweeps
client.dynamic_simulations
client.components
client.submissions
client.starred_components
client.compute_units
client.webhook_endpoints
client.fmu

Error handling

from thrustlab import Client
from thrustlab.exceptions import (
    AuthenticationError,
    ValidationError,
    RateLimitError,
    NotFoundError,
)

client = Client()
try:
    client.simulations.create(project_id="proj_xxx", rotor_groups=[...], ...)
except ValidationError as exc:
    print(f"bad request: {exc.code} ({exc.param}): {exc.message}")
except RateLimitError as exc:
    print(f"rate limited; retry after {exc.retry_after}s")
except NotFoundError as exc:
    print(f"not found: {exc.message}")
except AuthenticationError as exc:
    print(f"auth failed: {exc.message}")

Every error carries .code, .type, .request_id, .http_status, and .message. ValidationError additionally exposes .param. See thrustlab.com/docs/guides/errors for the full code reference.

Pagination

List endpoints return a CursorPager — a lazy iterator that fetches the next page only when needed:

# Iterate all pages automatically
for project in client.projects.list():
    print(project["id"])

# Materialise the first page only
first_page = list(client.projects.list(limit=20))

Async polling

simulations.wait(), sweeps.wait(), and dynamic_simulations.wait() block until the resource reaches a terminal state (completed, failed, or canceled — one 'l' on the wire) or the timeout fires. On timeout the returned dict carries the SDK-side sentinel status="timed_out" (never a server state):

sweep = client.sweeps.create(...)
result = client.sweeps.wait(sweep["id"], timeout=600, poll_interval=2.0)
if result["status"] == "completed":
    for point in client.sweeps.list_points(sweep["id"]):
        print(point["rotors"]["1"]["thrust_n"])

Webhooks

from thrustlab import Webhook
from thrustlab.exceptions import SignatureVerificationError

WEBHOOK_SECRET = "whsec_..."

@app.post("/webhooks/thrustlab")
async def handle(request):
    payload = await request.body()
    sig    = request.headers["Thrustlab-Signature"]
    try:
        event = Webhook.verify(payload, sig, WEBHOOK_SECRET)
    except SignatureVerificationError:
        return Response(status_code=400)
    if event.type == "simulation.succeeded":
        print(event.data)

Retries

The client automatically retries on 429 (rate limit) and 5xx responses using exponential backoff with jitter. Set max_retries=0 to disable:

client = Client(max_retries=0)

License

Apache-2.0. See LICENSE and NOTICE.

Metadata

Release files for thrustlab 0.6.0

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

Source distribution (sdist)

Source distribution for thrustlab 0.6.0
File Size Uploaded
thrustlab-0.6.0.tar.gz 328.8 kB Details

Built distribution (wheel)

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

Total release size: 649.6 kB

Release files / thrustlab-0.6.0.tar.gz

Download URL thrustlab-0.6.0.tar.gz
Size 328.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e88abf8f0dbe4eadda0024fec1807765fda5df92b9591085f821d1764a225aef
BLAKE2b-256 checksum
How to use checksums
abe667e0d2dca769db573df178eb9f6f0c436a31596aa5b8eb3af8848a7b7abd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / thrustlab-0.6.0-py3-none-any.whl

Download URL thrustlab-0.6.0-py3-none-any.whl
Size 320.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
640f1177be0517174db53bf80c42f9e5fa0e1ca5cb74bff28c58731740002ace
BLAKE2b-256 checksum
How to use checksums
ae5e61a6017b8b97b5b73c1c719003ddaf6894a67a0832fa255ca73e5e496efe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

0.7.0

2 release files

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.1.1

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