Skip to main content

JSON-driven PDF generation over ReportLab

Project description

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 GitHub without installing it permanently. Perfect for one-off usage or testing.

Using uvx (Recommended - Fast)

# Run once without installing
uvx --from git+https://github.com/Shubhamnegi/reportlab-json-renderer.git pdf-renderer --help

# Render a PDF directly from GitHub
uvx --from git+https://github.com/Shubhamnegi/reportlab-json-renderer.git pdf-renderer render --input report.json --output report.pdf

Using pipx

# Run once without installing
pipx run git+https://github.com/Shubhamnegi/reportlab-json-renderer.git --help

# Or install permanently from GitHub
pipx install git+https://github.com/Shubhamnegi/reportlab-json-renderer.git
pdf-renderer --help

From Local Clone

# 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.

Project details


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.1.0.tar.gz (86.8 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.1.0-py3-none-any.whl (65.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: reportlab_json_renderer-0.1.0.tar.gz
  • Upload date:
  • Size: 86.8 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.1.0.tar.gz
Algorithm Hash digest
SHA256 8095e55bdd8ddb694f0a32da6ba1ec800fe3708964eef22f5ec15ec0d1558fd1
MD5 58388388b58a6bb53fee1b0959afb116
BLAKE2b-256 215d672e750290eb3117e713d611eca432894087906715e42f7a61ae2e4f68db

See more details on using hashes here.

Provenance

The following attestation bundles were made for reportlab_json_renderer-0.1.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.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for reportlab_json_renderer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e2f521238e5c28ecfed9a63501767536615f49ed0098b6652379b0b3f81e2e73
MD5 0f32898f430bb492668fe2ea5ed8eb3f
BLAKE2b-256 46d9ad2f95fa710baa78acab5aba9e72543c7be97c776c8aa6d5d50342f2537e

See more details on using hashes here.

Provenance

The following attestation bundles were made for reportlab_json_renderer-0.1.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.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page