Library to interact with PrusaLink v2
Project description
pyprusalink
Async Python client for the PrusaLink HTTP API. Covers both the current /api/v1/... endpoints and a few legacy paths (/api/version, /api/printer).
The primary consumer is the Home Assistant prusalink integration, and API shape decisions are weighted toward serving that integration. Today the library does not perform runtime validation, retry, or caching at the boundary — consumers handle those — but the shape may evolve as the integration's needs do.
Requirements
- Python 3.11+
- A PrusaLink-enabled Prusa printer (bundled with Prusa-Firmware-Buddy on Core One, MK4, MK3.9, MK3.5, MINI, XL; or standalone PrusaLink on an RPi)
The library is async-only and is built on httpx. Digest authentication is handled by httpx.DigestAuth under the hood.
Installation
pip install pyprusalink
Quickstart
import asyncio
import httpx
from pyprusalink import PrusaLink
async def main() -> None:
async with httpx.AsyncClient() as client:
api = PrusaLink(client, "http://prusa.local", "maker", "<password>")
info = await api.get_info()
print(info.get("name"), info.get("serial"))
status = await api.get_status()
print(status["printer"]["state"])
job = await api.get_job()
if job is not None:
print(f"{job['progress']:.0f}% — {job['file']['display_name']}")
asyncio.run(main())
The username on bundled-firmware printers is maker. The password is the API key shown under Settings → PrusaLink on the printer.
Public API
| Method | Returns | Notes |
|---|---|---|
get_version() |
VersionInfo |
/api/version — firmware, hostname, API version |
get_info() |
PrinterInfo |
/api/v1/info — serial, model, location, capabilities |
get_status() |
PrinterStatus |
/api/v1/status — printer state plus embedded job/storage/transfer/camera |
get_job() |
JobInfo | None |
/api/v1/job — None when no job is running |
get_storage() |
list[Storage] |
/api/v1/storage — available storage devices |
get_transfer() |
Transfer | None |
/api/v1/transfer — None when no transfer is in progress |
cancel_transfer(transfer_id) |
None |
Cancel an active upload |
cancel_job(job_id) |
None |
Cancel a print |
pause_job(job_id) |
None |
Pause a running print |
resume_job(job_id) |
None |
Resume a paused print |
continue_job(job_id) |
None |
Continue after the printer enters the ATTENTION state (e.g. timelapse capture) |
get_legacy_printer() |
LegacyPrinterStatus |
/api/printer — legacy endpoint, used for material |
get_file(path) |
bytes |
Fetch raw resources such as thumbnails referenced from JobFilePrint.refs |
Errors
All HTTP errors map to subclasses of PrusaLinkError:
| Exception | When |
|---|---|
InvalidAuth |
401 — wrong credentials |
NotFound |
404 — resource missing |
Conflict |
409 — action conflicts with current printer state (e.g. cancel while idle) |
from pyprusalink.types import Conflict
try:
await api.cancel_job(42)
except Conflict:
... # printer wasn't in a cancellable state
Type contract
Return types are TypedDicts declared in pyprusalink/types.py. Two conventions worth knowing:
-
NotRequired[T]for optional fields. The PrusaLink API omits absent fields rather than returningnull, so optional fields areNotRequired[T]and consumers must use.get(...)or membership checks. Indexing a missing key raisesKeyError. -
T | Nonefor return types when the resource may be absent.get_job()andget_transfer()returnNone(not an emptydict) when there's no active job/transfer.
The library does not perform runtime validation. response.json() results are wrapped in typing.cast(...) against the declared TypedDict. This is a deliberate choice — for a thin wrapper, the runtime overhead and dependency footprint of pydantic/msgspec is not worth it. If you need runtime validation, layer it on top.
Versioning
Semantic versioning. Changes to TypedDict shapes that affect strict-typed consumers are counted as breaking and require a major version bump.
Development
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[test,lint]"
# unit tests (default — integration tests are excluded)
pytest tests/
# lint
black --check pyprusalink/ tests/
flake8 pyprusalink/ tests/
isort --check pyprusalink/ tests/
mypy
Integration tests
Integration tests live in tests/test_integration.py and run against a real printer. They are opt-in via the integration pytest marker:
PRUSALINK_HOST=http://prusa.local \
PRUSALINK_USERNAME=maker \
PRUSALINK_PASSWORD=<api-key> \
pytest tests/test_integration.py -m integration
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyprusalink-3.0.0.tar.gz.
File metadata
- Download URL: pyprusalink-3.0.0.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df984296e4689f6085c9515fba7f664225ca986d828c69d3eb53c63650a4e523
|
|
| MD5 |
716d75dd22e143583a77ef19882ef6eb
|
|
| BLAKE2b-256 |
10975b8e5d0e9dfc080caf29d99caee7f51d592e82266e4ddaf9ee9211b8a06c
|
File details
Details for the file pyprusalink-3.0.0-py3-none-any.whl.
File metadata
- Download URL: pyprusalink-3.0.0-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66691f62c8c14399ed0d7d6a7c8768ae7ab47402f6987a2c50967c77b1b28d1b
|
|
| MD5 |
90858c6dba58ac84f8366513a89cbc5b
|
|
| BLAKE2b-256 |
33a0bb420aac58e61dacefc768bc4ca4388f7a37c11eb7efef9a95e672d6263e
|