quirepdf (Python)
Send JSON, get back a polished PDF. Python 3.9+, standard library only, synchronous.
Install
pip install quirepdf
Quickstart
Any JSON object renders. Quire picks the best-matching template, or a clean generic layout:
from quirepdf import Quire
client = Quire() # reads QUIRE_API_KEY (and QUIRE_API_URL)
order = {
"order_id": "ORD-88213",
"customer": {"name": "Lena Fischer", "email": "lena@example.de"},
"lines": [{"sku": "TS-BLK-M", "name": "Organic tee", "qty": 2, "price": 29.0}],
"currency": "€",
}
result = client.render(order)
result.save("order.pdf")
print(result.template, result.template_source, result.pages) # document fallback 1
if result.hint:
print("almost matched:", result.hint) # e.g. "invoice (seller is required)"
Name a template and use the generated types so your editor checks the fields:
from quirepdf.types import InvoiceData
invoice: InvoiceData = {
"number": "INV-2026-0142",
"issued": "1 Oct 2026",
"due": "15 Oct 2026",
"seller": {"name": "Northwind Studio", "address": ["221 Market Street", "San Francisco, CA 94105"]},
"customer": {"name": "Ravi Kumar", "address": ["14 Residency Road", "Bengaluru 560025"]},
"items": [{"description": "Pro plan", "qty": 1, "unit_price": 49}],
"status": "due", # Literal["draft", "due", "paid", "overdue", "void"]
}
pdf = client.render(invoice, template="invoice")
png = client.render(invoice, template="invoice", format="png", page=1) # preview one page
print(pdf.content[:5], len(png.content), pdf.render_ms, pdf.quota) # Quota(limit=100, remaining=97)
RenderResult fields: content (the file as bytes), content_type, pages, template,
template_source (explicit | detected | fallback), hint, render_ms, quota, and save(path).
Other calls:
check = client.validate(invoice, template="invoice") # free, nothing rendered
check.valid, check.errors # False, [{"path": "...", "message": "..."}]
client.templates.list() # [{"name": "invoice", "title": "Invoice", ...}, ...]
client.templates.get("invoice") # {"template": {...}, "schema": {...}, "sample": {...}}
client.usage() # {"plan": "free", "used": 3, "limit": 100, "remaining": 97, ...}
new = client.keys.create(name="ci") # new["api_key"] is shown only once
client.keys.list() # [{"id", "prefix", "name", "current": bool, ...}]
client.keys.revoke(new["key"]["id"])
Errors
Every failure raises QuireError with status, type, message and fields:
from quirepdf import QuireError
try:
client.render({"number": "INV-1"}, template="invoice")
except QuireError as err:
print(err.status, err.type) # 422 invalid_data
print(err) # data has 5 problems
# - issued is required
# - due is required ...
for f in err.fields:
print(f["path"], f["message"])
Common types: invalid_data, unknown_template, unauthorized, quota_exceeded, bad_request,
payload_too_large, timeout. Client-side failures have status == 0: type == "network"
(can't connect) or type == "timeout" (no reply within timeout seconds). The SDK never retries.
Configuration
| Argument | Environment | Default |
|---|---|---|
api_key |
QUIRE_API_KEY |
none (no Authorization header is sent) |
base_url |
QUIRE_API_URL |
https://api.quirepdf.dev |
timeout |
30.0 seconds |
client = Quire(api_key="qk_...", base_url="http://127.0.0.1:8787", timeout=10)
A local engine in open mode (make serve) needs no key.
Development
python3 scripts/gen_types.py # regenerate src/quirepdf/types.py after a schema change
python3 scripts/gen_types.py --check # fail if it is stale
PYTHONPATH=src python3 -m unittest discover -s tests -v # runs against engine/target/release/quire-engine (make build)
Metadata
Release files for quirepdf 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| quirepdf-0.1.0.tar.gz | 12.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quirepdf-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.3 kB
Release files / quirepdf-0.1.0.tar.gz
| Download URL | quirepdf-0.1.0.tar.gz |
|---|---|
| Size | 12.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fab20a68b5ccf23769fa14597d80c88f88f7c8510b7130970b8be380564acbc5
|
|
BLAKE2b-256 checksum How to use checksums |
93123c9cd99de7c0b9289c223a4f9bc75614b6c858f09d1c16e4a700cf3f77d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / quirepdf-0.1.0-py3-none-any.whl
| Download URL | quirepdf-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7cd3a8b844c8104d9971feeafdee159d5581c89015594b0bda512777725c67b1
|
|
BLAKE2b-256 checksum How to use checksums |
ed9912ccab46a94e79b1eff974310d7bbdd9012125fd6a25f36d5c2d85a3e005
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|