Python
The Calco client is a standard-library-only connector for Python 3.8+. It converts templates to PDF, HTML, CSV, ODS, and XLS with optional JSON data injection.
Add the connector
There's no PyPI package to install (yet) — the client is a small,
standard-library-only package. Copy the calco/ connector directory
(client.py and __init__.py) into your project, keeping the package name, so
the import below resolves:
from calco import CalcoClientQuick start
from calco import CalcoClient
client = CalcoClient("http://localhost:8080", api_key="dc_live_...")
# Convert a local XLSX file to PDF
pdf_bytes = client.convert("invoice_template.xlsx", format="pdf", data={"total": 100})
with open("invoice.pdf", "wb") as f:
f.write(pdf_bytes)The constructor is CalcoClient(base_url, timeout=120, api_key=None). The key is
sent as Authorization: Bearer <key> on every request.
Converting a file
convert uploads a local file and returns the rendered bytes without storing
anything. data accepts a dict or list and is serialized for you.
html = client.convert(
"report.xlsx",
format="html", # "pdf" | "html" | "csv" | "ods" | "xls"
data={"quarter": "Q1", "revenue": 50000},
sheet="Summary",
title="Q1 Report",
)Extract the placeholder map with scaffold:
scaffold = client.scaffold("invoice_template.xlsx")Managing templates
# Create
template = client.create_template(
"invoice_v1.xlsx",
name="Invoice",
category="finance",
tags="billing,invoice",
)
# List
templates = client.list_templates()
# Update metadata (only supplied fields change)
client.update_template(template_id=1, name="Invoice (updated)", tags="billing,v2")
# Add a new version
version = client.add_version(template_id=1, file_path="invoice_v2.xlsx")
# Scaffold for a specific version
scaffold = client.get_version_scaffold(template_id=1, version=2)
# Delete
client.delete_template(template_id=1)Rendering a stored template
Render via POST with render_template, or fetch via GET with
download_template:
pdf = client.render_template(
template_id=1,
version=2,
data={"customer": "Acme Corp", "total": 1500},
format="pdf",
title="Invoice #1234",
)
with open("invoice_1234.pdf", "wb") as f:
f.write(pdf)Batch rendering
Render a list of records into a single ZIP archive:
records = [
{"customer": "Acme Corp", "total": 1500},
{"customer": "Globex Inc", "total": 2300},
]
zip_bytes = client.batch_render(
template_id=1,
records=records,
format="pdf",
title_template="Invoice-{customer}",
version=2,
)
with open("invoices.zip", "wb") as f:
f.write(zip_bytes)By-hash workflow
Every stored version exposes a content hash (sha256 of the file). Address a
version directly by hash:
meta = client.get_template_by_hash("3c9f...d1ab")
pdf = client.render_by_hash("3c9f...d1ab", data={"customer": "Jane"}, format="pdf")
xlsx = client.download_by_hash("3c9f...d1ab", format="xlsx")Error handling
HTTP errors raise CalcoError, carrying the status code and message:
from calco import CalcoClient, CalcoError
client = CalcoClient("http://localhost:8080")
try:
client.delete_template(999)
except CalcoError as e:
print(e.status_code) # 404
print(e.message) # "Template not found"Framework integration
Django
# views.py
from django.http import HttpResponse
from calco import CalcoClient
client = CalcoClient("http://calco-service:8080")
def download_invoice(request, invoice_id):
invoice = Invoice.objects.get(pk=invoice_id)
pdf = client.render_template(
template_id=invoice.template_id,
version=invoice.template_version,
data={
"customer": invoice.customer_name,
"items": [
{"description": li.description, "amount": str(li.amount)}
for li in invoice.lines.all()
],
"total": str(invoice.total),
},
format="pdf",
title=f"Invoice #{invoice.number}",
)
response = HttpResponse(pdf, content_type="application/pdf")
response["Content-Disposition"] = f'attachment; filename="invoice_{invoice.number}.pdf"'
return responseFastAPI
# main.py
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
from calco import CalcoClient, CalcoError
app = FastAPI()
client = CalcoClient("http://calco-service:8080")
@app.get("/invoices/{invoice_id}/pdf")
async def get_invoice_pdf(invoice_id: int):
invoice_data = get_invoice_from_db(invoice_id)
try:
pdf = client.render_template(
template_id=invoice_data["template_id"],
version=invoice_data["template_version"],
data=invoice_data["fields"],
format="pdf",
title=f"Invoice #{invoice_id}",
)
except CalcoError as e:
raise HTTPException(status_code=e.status_code, detail=e.message)
return Response(
content=pdf,
media_type="application/pdf",
headers={"Content-Disposition": f'attachment; filename="invoice_{invoice_id}.pdf"'},
)