Mail merge and bulk document generation from CSV to PDF using WeasyPrint and Jinja2.
Project description
WeasyMerge is a tool for doing mail merges and other bulk document generation without having to write your own glue code. You get the power of WeasyPrint's best-in-class PDF generation with the ease of writing a Jinja2 template with some HTML/CSS and providing a CSV file of data to merge.
WeasyMerge can generate individual PDFs or batch rows together into one or more PDFs.
Installation
WeasyMerge is a command-line tool, so the easiest way to install it is with pipx or uv:
pipx install weasymerge
uv tool install weasymerge
You can also install it into an existing environment with pip:
pip install weasymerge
WeasyMerge relies on WeasyPrint, which needs some system libraries — see its installation guide. On Windows this is much smoother under WSL.
Usage
weasymerge --data guests.csv --template invite.html.j2 --output "pdfs/Invite {row_number} {row[Name]}.pdf"
pipx run and uvx run WeasyMerge on demand, fetching it if it isn't already
available, so you can invoke it without installing it first:
pipx run weasymerge --data guests.csv --template invite.html.j2 --output "pdfs/Invite {row_number} {row[Name]}.pdf"
uvx weasymerge --data guests.csv --template invite.html.j2 --output "pdfs/Invite {row_number} {row[Name]}.pdf"
The first row of the CSV file is assumed to be the header row and the header is used as the key for the row dictionary.
HTML escaping is on by default in the Jinja2 template.
The row number for the first data row is 1.
WeasyMerge provides "safe" row data to the output filename template (ASCII letters, digits, space, underscore, hyphen, and dot). Non-ASCII letters are converted to their closest ASCII equivalent.
Batch mode (multiple rows per document)
Pass --rows-per-document=N to render N rows into a single document,
or --rows-per-document=all to render every row into one document.
Use this for label sheets, ID cards, or any layout where the
template needs to see more than one row at a time.
weasymerge --data seeds.csv --template labels.html.j2 \
--output "labels-{batch.from_row_number}-{batch.to_row_number}.pdf" \
--rows-per-document=all
In batch mode the template receives a batch object instead of
row and row_number:
batch.rows— list of row dicts in this batchbatch.numbered_rows— list of(row_number, row)pairsbatch.from_row_number,batch.to_row_number— 1-indexed inclusive rangebatch.total_rows— total rows in the source data
The same fields are available in the --output template (e.g.
{batch.from_row_number}, {batch.rows[0][Plant]}). Page breaks
within a single document are the template's responsibility — use
CSS page-break-after: always or break-after: page.
See examples/labels/ for a 70×37mm, 24-per-A4 label sheet.
Barcodes and QR codes
WeasyMerge comes with barcode and QR code Jinja2 filters, powered by pyStrich.
Each filter turns a value into a data: URL you can drop straight into an
<img> tag in your template:
<img src="{{ row['TicketID'] | qrcode_svg_dataurl }}" alt="Ticket QR code">
The available filters are:
qrcode_svg_dataurldatamatrix_svg_dataurlaztec_svg_dataurlpdf417_svg_dataurlcode128_svg_dataurlean13_svg_dataurlcode39_svg_dataurl
See examples/tickets/ for A6 event tickets with a QR code and a Code128
barcode.
Project details
Release history Release notifications | RSS feed
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 weasymerge-0.1.0.tar.gz.
File metadata
- Download URL: weasymerge-0.1.0.tar.gz
- Upload date:
- Size: 57.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13dbdbf4952503d658f15e5d812c93064880404019470371badaf4955a17f3e9
|
|
| MD5 |
47f3eb9360af5725f204b49850ba45ea
|
|
| BLAKE2b-256 |
f6ceabe6af7e9dbd8bb713ce41a4ea65e1aaf9d91a9421b73cfa54851e1f50ea
|
Provenance
The following attestation bundles were made for weasymerge-0.1.0.tar.gz:
Publisher:
python-release.yml on mmulqueen/weasymerge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
weasymerge-0.1.0.tar.gz -
Subject digest:
13dbdbf4952503d658f15e5d812c93064880404019470371badaf4955a17f3e9 - Sigstore transparency entry: 2035360829
- Sigstore integration time:
-
Permalink:
mmulqueen/weasymerge@b65e7378584c5040fa83381a106c9065bac4491b -
Branch / Tag:
refs/tags/v0.1 - Owner: https://github.com/mmulqueen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@b65e7378584c5040fa83381a106c9065bac4491b -
Trigger Event:
release
-
Statement type:
File details
Details for the file weasymerge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: weasymerge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af1328c47499fc29cd48ae951429b9cc25f3af097ec31ca5d0c16fb728a3ff29
|
|
| MD5 |
f9405771cf3598a257a9d100890a5e76
|
|
| BLAKE2b-256 |
fd73ea6450f93211c39bb5184d7598a2bfe6c0d851eaef6938225c65335b76a9
|
Provenance
The following attestation bundles were made for weasymerge-0.1.0-py3-none-any.whl:
Publisher:
python-release.yml on mmulqueen/weasymerge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
weasymerge-0.1.0-py3-none-any.whl -
Subject digest:
af1328c47499fc29cd48ae951429b9cc25f3af097ec31ca5d0c16fb728a3ff29 - Sigstore transparency entry: 2035361011
- Sigstore integration time:
-
Permalink:
mmulqueen/weasymerge@b65e7378584c5040fa83381a106c9065bac4491b -
Branch / Tag:
refs/tags/v0.1 - Owner: https://github.com/mmulqueen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@b65e7378584c5040fa83381a106c9065bac4491b -
Trigger Event:
release
-
Statement type: