TofuPilot Python SDK
The official Python SDK for TofuPilot. Integrate your hardware test runs into one app with just a few lines of Python.
Installation
pip install tofupilot
Quick Start
import os
from tofupilot.v2 import TofuPilot
with TofuPilot(api_key=os.getenv("TOFUPILOT_API_KEY")) as client:
run = client.runs.create(
procedure_id="your-procedure-id",
serial_number="SN001",
part_number="PN001",
outcome="PASS",
)
print(f"Run created: {run.id}")
Authentication
Set your API key as an environment variable:
export TOFUPILOT_API_KEY="your-api-key"
Or pass it directly:
client = TofuPilot(api_key="your-api-key")
To point to a different server (e.g. self-hosted):
client = TofuPilot(api_key="your-api-key", server_url="https://your-instance.com/api")
Available Resources
| Resource | Operations |
|---|---|
client.runs |
list, create, get, delete, update |
client.runs.attachments |
upload, download |
client.units |
list, create, get, delete, update, add_child, remove_child |
client.units.attachments |
upload, download, delete |
client.parts |
list, create, get, delete, update |
client.parts.revisions |
create, get, delete, update |
client.procedures |
list, create, get, delete, update |
client.procedures.versions |
create, get, delete |
client.batches |
list, create, get, delete, update |
client.stations |
list, create, get, get_current, remove, update |
client.user |
list |
Usage Examples
Create a run with measurements
from datetime import datetime, timedelta, timezone
run = client.runs.create(
procedure_id=procedure_id,
serial_number="SN-001",
part_number="PCB-V1",
outcome="PASS",
started_at=datetime.now(timezone.utc) - timedelta(minutes=5),
ended_at=datetime.now(timezone.utc),
phases=[{
"name": "Voltage Test",
"outcome": "PASS",
"started_at": datetime.now(timezone.utc) - timedelta(minutes=5),
"ended_at": datetime.now(timezone.utc),
"measurements": [{
"name": "Output Voltage",
"outcome": "PASS",
"measured_value": 3.3,
"units": "V",
"validators": [
{"operator": ">=", "expected_value": 3.0},
{"operator": "<=", "expected_value": 3.6},
],
}],
}],
)
List and filter runs
result = client.runs.list(
part_numbers=["PCB-V1"],
outcomes=["PASS"],
limit=10,
)
for run in result.data:
print(f"{run.id} — {run.unit.serial_number}")
Manage units and sub-units
# Create part and revision
client.parts.create(number="PCB-V1", name="Main Board")
client.parts.revisions.create(part_number="PCB-V1", number="REV-A")
# Create units
client.units.create(serial_number="PARENT-001", part_number="PCB-V1", revision_number="REV-A")
client.units.create(serial_number="CHILD-001", part_number="PCB-V1", revision_number="REV-A")
# Link parent-child
client.units.add_child(serial_number="PARENT-001", child_serial_number="CHILD-001")
Attach files to runs and units
# Upload a file to a run
client.runs.attachments.upload(id=run_id, file="report.pdf")
# Upload a file to a unit
client.units.attachments.upload(serial_number="SN-0001", file="calibration.pdf")
# Download an attachment
run = client.runs.get(id=run_id)
client.runs.attachments.download(run.attachments[0], dest="local-copy.pdf")
# Delete a unit attachment
client.units.attachments.delete(serial_number="SN-0001", ids=[attachment_id])
Error Handling
from tofupilot.v2.models.errors import ErrorNOTFOUND, ErrorBADREQUEST
try:
client.runs.get(id="nonexistent-id")
except ErrorNOTFOUND as e:
print(f"Not found: {e.message}")
except ErrorBADREQUEST as e:
print(f"Bad request: {e.message}")
| Exception | Status Code |
|---|---|
ErrorBADREQUEST |
400 |
ErrorUNAUTHORIZED |
401 |
ErrorFORBIDDEN |
403 |
ErrorNOTFOUND |
404 |
ErrorCONFLICT |
409 |
ErrorUNPROCESSABLECONTENT |
422 |
ErrorINTERNALSERVERERROR |
500 |
Running Tests
cd clients/python-speakeasy
cp tests/.env.local.example tests/.env.local # Set your API key and URL
python -m pytest tests/v2/
Documentation
License
MIT
Metadata
Release files for tofupilot 2.14.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tofupilot-2.14.1.tar.gz | 135.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tofupilot-2.14.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 355.5 kB
Release files / tofupilot-2.14.1.tar.gz
| Download URL | tofupilot-2.14.1.tar.gz |
|---|---|
| Size | 135.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
23f51f2538b6571afcffec425d6672c4222f52af0b26d1a0c24c1417825a1cac
|
|
BLAKE2b-256 checksum How to use checksums |
8ecf6cb4cc3b50bfd0aff4ae7882aa7c3d58be47e9e4060d3400953c2a4e2619
|
| 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 Aug 6, 2026.
Transparency logRelease files / tofupilot-2.14.1-py3-none-any.whl
| Download URL | tofupilot-2.14.1-py3-none-any.whl |
|---|---|
| Size | 219.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8f8d0c0838850d1d772c098852ffe4d6c30bfb95d9473956087c317913d22518
|
|
BLAKE2b-256 checksum How to use checksums |
5645709f4814d0a52c5828d46cbf2770994b3919c0534f9d70cb98a04beef22b
|
| 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 Aug 6, 2026.
Transparency log