Typst from Python
Tip
Make sure to check the overview of how and why Typst can be used from programming languages to fully understand it.
In Python, the recommended binding to use is typst-py, maintained by messense, a Maturin developer (the software that allows Python and Rust to communicate), which is a very good thing.
Please also note that Python integrates well with Quarto, which offers a convenient and highly customizable way to create reports with Typst. You can find a dedicated tutorial here.
Installation¶
Usage¶
Basically, it mainly offers a compile() function that we can use like this:
We can pass info from Python to Typst using the sys_inputs argument in a JSON-like manner:
import json
import typst
humans = [{"name": "Joseph", "age": 25}, {"name": "Justine", "age": 24}]
sys_inputs = {"humans": json.dumps(humans)}
typst.compile(input="file.typ", output="file.pdf", sys_inputs=sys_inputs)
On the Typst side, we can read those inputs with:
#let humans = json(bytes(sys.inputs.humans))
#for human in humans [
#human.name is #human.age years old. \
]
By being able to pass variables from Python to Typst, it enables us to connect our Python logic directly to the PDF output that will be rendered to the user.
Example with FastAPI¶
Here is an example that creates a FastAPI /report endpoint with a color argument that returns a PDF report, made with Typst relying on that parameter for the style.
First, we create a basic Typst file:
#let col = json(bytes(sys.inputs.color))
#set page(fill: rgb(col), width: 10cm, height: 5cm)
= Dynamic Typst report made with Python
Then a minimalist FastAPI app:
from pathlib import Path
from fastapi import FastAPI
from fastapi.responses import FileResponse
import typst
app = FastAPI()
@app.get("/report")
def report(color: str):
path_typst = "file.typ"
path_pdf = "file.pdf"
sys_inputs = {"color": json.dumps(color)}
typst.compile(
path_typst,
output=path_pdf,
sys_inputs=sys_inputs,
)
return FileResponse(Path(report_path))
Other resources¶
typst-py is probably the most useful tool to combine Typst and Python, but other projects are worth mentioning as they can solve different use cases:
pyrunner: a Typst package that lets you run Python code (stdlib only) inside Typst.
#import "@preview/pyrunner:0.3.0" as py
#let compiled = py.compile(
```python
def find_emails(string):
import re
return re.findall(r"\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b", string)
def sum_all(*array):
return sum(array)
```)
#let txt = "My email address is john.doe@example.com and my friend's email address is jane.doe@example.net."
#py.call(compiled, "find_emails", txt)
#py.call(compiled, "sum_all", 1, 2, 3)
pyst: a Python package designed to generate Typst code in Python.
import pypst
heading = pypst.Heading("My Heading", level=2)
print(heading.render()) # prints: "== My Heading"
typstpy: a Python package to generate Typst code, similar topyst.
Output is: #circle([Hello, world!], width: 100%, radius: 10pt).
Question
Know of other projects that would be a good fit here? Feel free to open an issue.