Skip to main content

reportlab-json-renderer

JSON-driven PDF generation over ReportLab.

An LLM/agent sends a compact JSON specification; this library validates it, resolves a template + theme, renders each block via ReportLab, and produces a polished PDF — no Python layout code is generated by the agent.

Requirements

  • Python ≥ 3.11

Installation

pip install reportlab-json-renderer

For development (includes pytest, ruff, pre-commit):

pip install -e ".[dev]"

Quick Run (No Installation Needed)

Run the CLI directly from PyPI without installing it permanently. Perfect for one-off usage or testing.

Using uvx (Recommended - Fast)

# Run once without installing
uvx --from reportlab-json-renderer pdf-renderer --help

# Render a PDF directly from PyPI
uvx --from reportlab-json-renderer pdf-renderer render --input report.json --output report.pdf

Using pipx

# Run once without installing
pipx run reportlab-json-renderer --help

# Or install permanently from PyPI
pipx install reportlab-json-renderer
pdf-renderer --help

From Local Clone (Development)

# If you have the repo cloned locally
uvx --from . pdf-renderer --help
pipx run . pdf-renderer --help

Quick Start

Python API

from reportlab_json_renderer import render_pdf

result = render_pdf(spec=my_json_spec, output_path="/tmp/report.pdf")
print(result["path"], result["pages"])

CLI

# Render a spec to PDF
pdf-renderer render --input report.json --output report.pdf

# Validate without rendering
pdf-renderer validate --input report.json

# Export the JSON Schema
pdf-renderer schema --output schema.json

# List available templates
pdf-renderer templates

# List registered block types
pdf-renderer blocks

# Generate a sample spec
pdf-renderer sample --output sample.json

Why JSON-Driven PDFs?

When an LLM/agent needs to generate PDFs, there are three common approaches. This library is purpose-built for the agent workflow and outperforms the alternatives on safety, token efficiency, and determinism.

vs. Direct ReportLab Code Generation

The agent writes Python that imports ReportLab, creates a canvas, and places flowables. This is the default "just write code" approach.

Dimension Agent-generated ReportLab code reportlab-json-renderer
Token usage ~4,000–6,000 tokens for a 10-page report ~800–1,200 tokens (~70% fewer)
Security Agent emits executable Python — os.system(), file writes possible Agent never writes code; JSON is declarative and sandboxed
Error surface SyntaxError, AttributeError from malformed generated code Schema validation catches issues before rendering
Consistency Same spec → different layout each time (agent rewrites styles) Same spec → identical PDF every time
Maintainability Regenerated code varies per request; no single source of truth Block renderers, themes, and templates are versioned backend code
Debugging Stack traces point into generated code with no meaningful names Errors map to block type and renderer with clear messages

vs. HTML-to-PDF (WeasyPrint, wkhtmltopdf, Puppeteer)

The agent generates full HTML + CSS which is then converted to PDF.

Dimension HTML-to-PDF reportlab-json-renderer
Token usage ~3,000–4,000 tokens — verbose HTML structure + CSS ~800–1,200 tokens — compact JSON blocks
Layout control CSS is fragile — print media quirks, box model issues Backend-owned ReportLab rendering — deterministic output
Security Risk of injected <script>, external resource loading No executable code; asset_root blocks path traversal
Dependencies Chromium, WK binary, or C libs (libpango, etc.) Pure Python — reportlab + pydantic only
Reproducibility Browser/renderer version-dependent output drift Deterministic pipeline with golden-file tests
Branding CSS must be re-emitted every time Theme and template resolved server-side; agent picks "theme": "green"

Where the Token Savings Come From

The ~70% reduction comes from eliminating three categories of agent output:

  1. Style declarations — font sizes, colors, margins, padding → handled by themes and templates.
  2. Layout coordinates — x/y positioning, widths, heights → handled by ReportLab flowables and page templates.
  3. Boilerplate setup — imports, canvas creation, font registration → handled by the renderer pipeline.

The agent only describes what content to show (blocks, data, text), never how to lay it out.

Python API Reference

render_pdf(spec, output_path=None, allow_partial=False, asset_root=None)

Render a PDF from a validated JSON specification.

Parameters:

Name Type Description
spec dict JSON specification conforming to the report schema.
output_path str | None Filesystem path for the generated PDF. If None, returns bytes only.
allow_partial bool Continue after block render errors and return warnings instead of raising. Default: False.
asset_root str | Path | None Directory boundary for local images. Relative paths resolve under this root and traversal outside it is rejected. Default: current working directory.

Returns dict with keys:

Key Type Description
success bool True if rendering completed without errors.
path str | None Output file path, if written.
bytes bytes | None Raw PDF bytes when no output_path given.
pages int Number of pages in the generated PDF.
warnings list[str] Non-fatal warnings collected during render.
metadata dict Echo of template and theme used.

Warnings may come from schema post-validation checks, template block restrictions, or explicit partial-render mode (allow_partial=True).

Raises ValidationError if the spec fails validation and RenderError if a block cannot be rendered.

from reportlab_json_renderer import render_pdf

# Write to file
result = render_pdf(spec, output_path="/tmp/report.pdf")

# Bytes-only (no file written)
result = render_pdf(spec)
pdf_bytes = result["bytes"]

# Explicit partial rendering
result = render_pdf(spec, allow_partial=True)

# Restrict image loading to a known directory
result = render_pdf(spec, asset_root="/app/report-assets")

JSON Contract

See pdf-generator.md for the full specification. See docs/json-schema.md for a human-readable field reference.

Minimal example:

{
  "version": "1.0",
  "template": "analytics_report_v1",
  "theme": "green",
  "metadata": {
    "entity_name": "Demo Store",
    "report_title": "Weekly Report",
    "period": "11 Jun – 17 Jun 2026",
    "generated_at": "2026-06-18",
    "powered_by": "Public PDF Renderer",
    "confidential": true
  },
  "page": {
    "size": "A4",
    "orientation": "portrait",
    "margins": { "left_cm": 1.5, "right_cm": 1.5, "top_cm": 2.2, "bottom_cm": 2.0 }
  },
  "header": { "enabled": true, "variant": "default" },
  "footer": { "enabled": true, "show_page_number": true },
  "blocks": [
    { "type": "title", "entity": "Demo Store", "title": "Weekly Report", "subtitle": "11 Jun – 17 Jun 2026" }
  ]
}

An empty blocks list is valid and produces a single-page PDF with header and footer only.

Built-in Templates

Template Description
analytics_report_v1 Full-featured analytics report with charts, KPIs, and tables
business_report_v1 Professional business document with structured sections
compact_report_v1 Dense layout for data-heavy reports with minimal whitespace
invoice_v1 Compact invoice layout with tables and totals (limited block types)
proposal_v1 Sales proposal with hero sections and call-to-action blocks

Built-in Themes

Theme Description
green Green accent palette with dark text
neutral Professional grayscale palette
dark Dark background with light text

Block Types (19)

title, section_header, paragraph, rich_text, kpi_grid, callout, callout_group, table, matrix_table, insight_list, recommendations, image, chart, two_column, page_break, spacer, divider, badge, summary_box

Extending

This library is designed to be extended with custom blocks, themes, and templates.

Current implementation notes:

  • image blocks currently support local filesystem paths only.

  • Relative image paths are resolved under asset_root in the Python API and under the input JSON file's directory in the CLI. Traversal outside that root is rejected.

  • image.fit is accepted by the schema but not yet applied by the renderer.

  • Renders fail closed by default on block errors. Use allow_partial=True only if your application explicitly accepts partial output.

  • The renderer enables deterministic PDF generation settings where practical so repeated renders of the same spec can produce identical bytes.

  • Custom blocks: Subclass BaseBlock and register via the block registry. See docs/custom-blocks.md.

  • Custom themes: Create a Theme dataclass and register via the theme registry. See docs/custom-themes.md.

  • Custom templates: Create a Template dataclass and register via the template registry. See docs/custom-templates.md.

Development

# Lint
ruff check .

# Format
ruff format .

# Test
pytest

# Test with coverage
pytest --cov --cov-report=term-missing

# Rendered-PDF structural verification
pytest tests/test_golden.py

Project Structure

reportlab_json_renderer/
├── __init__.py          # Public API: render_pdf()
├── renderer.py          # Core rendering pipeline
├── cli.py               # CLI entry point
├── schema/              # Pydantic models & validators
│   ├── base.py          # ReportSpec, Block types, enums
│   └── validators.py    # validate_spec, generate_schema_json
├── templates/           # Report templates (5 built-in)
│   ├── base.py          # Template, PageSpec, build_template
│   └── registry.py      # get_template, register_template, list_templates
├── themes/              # Colour/font themes (3 built-in)
│   ├── base.py          # Theme, build_theme, DEFAULT_TONES
│   └── registry.py      # get_theme, register_theme, list_themes
├── blocks/              # Block type renderers (19 built-in)
│   ├── base.py          # BaseBlock ABC
│   └── registry.py      # render_block, register, list_registered
├── assets/              # Fonts, logos
├── utils/               # Colours, units, text, charts, images, errors
└── tests/
    └── fixtures/        # Test JSON files

Implementation Progress

See docs/implementation-checklist.md for the original build checklist and docs/release-readiness-checklist.md for current release work.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reportlab_json_renderer-0.3.0.tar.gz (155.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reportlab_json_renderer-0.3.0-py3-none-any.whl (81.4 kB view details)

Uploaded Python 3

File details

Details for the file reportlab_json_renderer-0.3.0.tar.gz.

File metadata

  • Download URL: reportlab_json_renderer-0.3.0.tar.gz
  • Upload date:
  • Size: 155.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for reportlab_json_renderer-0.3.0.tar.gz
Algorithm Hash digest
SHA256 7311da11a427de6fa4fe37db0662e0703b1b2a79a3d31135fe9f03659024b8d1
MD5 35fcb7fb8037dfa0c855ad5e4d916e64
BLAKE2b-256 9cdd7bc73fd83473197b8ff5d28390ff88dd8dfb55c560a130c5beac17629be4

See more details on using hashes here.

Provenance

The following attestation bundles were made for reportlab_json_renderer-0.3.0.tar.gz:

Publisher: publish.yml on Shubhamnegi/reportlab-json-renderer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file reportlab_json_renderer-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for reportlab_json_renderer-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e9c9b728908df01ba80b1b0d89527b331f0c713b8cd27a80599445a4fe363a1
MD5 440f28bdbc702fd217c0d22744e2b290
BLAKE2b-256 abccf813299155c477d6c4ff0a1bb120fcefc91d4c33afd0d8ddd37d16ab82fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for reportlab_json_renderer-0.3.0-py3-none-any.whl:

Publisher: publish.yml on Shubhamnegi/reportlab-json-renderer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page