WeasyPrint

Turns HTML and CSS into pixel-perfect PDFs using a pure-Python rendering engine built for print.

Library
PyPI
v69.0
9,545stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
88/100Excellent
Development Activity96
Maintenance84
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
84/100Excellent
Architecture88
Code Quality85
Innovation82
Learning Curve80

WeasyPrint is a Python library that renders HTML and CSS documents into PDF files without relying on a browser engine like WebKit or Chromium. It implements its own CSS layout engine in pure Python, purpose-built for pagination and print media, so page breaks, running headers/footers, and generated content behave the way the CSS Paged Media specification describes rather than approximating what a screen browser does.

Teams use it to turn HTML templates into invoices, reports, tickets, and other print-ready documents directly from application code, calling HTML(...).write_pdf() with no headless-browser process, GPU, or JavaScript runtime required. It builds on cffi bindings to Pango and HarfBuzz for text shaping and font handling, and supports advanced PDF output including PDF/A, PDF/UA, tagged (accessible) PDFs, and embedded fonts and attachments.

What You Get

  • A Python API (HTML, CSS, Document) for converting HTML/CSS into PDF bytes or files
  • A weasyprint command-line tool for one-off conversions without writing code
  • Support for CSS Paged Media features: page breaks, running headers/footers, page counters, and named pages
  • PDF/A, PDF/UA, and tagged (accessible) PDF output, plus custom metadata and file attachments
  • A pluggable URL fetcher for controlling how external images, fonts, and stylesheets are resolved

Common Use Cases

  • Invoice and receipt generation - SaaS billing systems render HTML invoice templates to PDF at checkout or on a schedule
  • Reporting pipelines - backend services turn HTML dashboards or data summaries into downloadable PDF reports
  • Ticket and badge printing - event platforms generate print-ready tickets or badges from HTML templates
  • Static site to PDF export - documentation or content sites offer a print/PDF version of a page without a headless browser

Under The Hood

Architecture WeasyPrint’s public API in weasyprint/__init__.py exposes HTML and CSS classes that parse a document with tinyhtml5/tinycss2 and cssselect2, then hand off to document.py’s Document._render, which drives the pipeline through formatting_structure/ (building the box tree from parsed HTML+CSS), layout/ (a large module set — block.py, flex.py, grid.py, table.py, page.py — that lays out boxes into paginated pages), and finally draw/ and pdf/ (rasterizing boxes and streaming PDF objects via the pydyf library). This is a classic multi-stage rendering pipeline (parse → box tree → layout → paint → PDF stream) with each stage in its own subpackage; changing the core box/layout abstraction in formatting_structure/boxes.py would ripple through every layout module and the drawing stage.

Tech Stack WeasyPrint is pure Python (3.10+) with cffi bindings (see weasyprint/text/ffi.py) to native HarfBuzz and Pango libraries for text shaping and font handling, tinyhtml5/tinycss2/cssselect2 for parsing and CSS selector matching, Pyphen for hyphenation, Pillow for image decoding, fonttools for font subsetting/embedding, and its sibling library pydyf for low-level PDF object writing. It ships a CLI entry point (weasyprint.__main__:main) built on the same public API, and CI (GitHub Actions, tests.yml) runs the test suite across Ubuntu, macOS, and Windows plus CPython 3.10–3.14 and PyPy.

Code Quality The project has an extensive tests/ suite covering the public API (test_api.py), CSS parsing, box construction, layout, drawing, fonts, and Unicode handling, using pytest with a custom PNG-rendering fixture (conftest.py, built on Ghostscript) for visual regression comparisons. Linting is enforced via ruff with an extensive rule set configured in pyproject.toml. Naming and typing follow standard Python conventions without extensive type hints; error handling favors explicit logger warnings (LOGGER/PROGRESS_LOGGER) over silent failure for malformed CSS/HTML input.

API Design The public surface is deliberately small: HTML(...), optional CSS(...) stylesheets, and .write_pdf()/.render() methods, with a single DEFAULT_OPTIONS dict documented inline covering PDF variant, metadata, image optimization, and accessibility options. Getting started requires almost no boilerplate — one HTML(string=...).write_pdf('out.pdf') call — while advanced needs (custom URL fetching, font configuration, PDF finishers) are opt-in via keyword arguments rather than subclassing, keeping the common path simple and the advanced path discoverable through the docstrings and Sphinx documentation.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search