Metadata-Version: 2.4
Name: reportlab-json-renderer
Version: 0.1.0
Summary: JSON-driven PDF generation over ReportLab
Project-URL: Homepage, https://github.com/reportlab-json-renderer/reportlab-json-renderer
Project-URL: Documentation, https://github.com/reportlab-json-renderer/reportlab-json-renderer#readme
Project-URL: Repository, https://github.com/reportlab-json-renderer/reportlab-json-renderer
Project-URL: Issues, https://github.com/reportlab-json-renderer/reportlab-json-renderer/issues
Project-URL: Changelog, https://github.com/reportlab-json-renderer/reportlab-json-renderer/blob/main/CHANGELOG.md
Author: Maintainers
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup
Requires-Python: >=3.11
Requires-Dist: matplotlib<4,>=3.8
Requires-Dist: pydantic<3,>=2.0
Requires-Dist: reportlab<5,>=4.0
Provides-Extra: dev
Requires-Dist: pre-commit<4,>=3.7; extra == 'dev'
Requires-Dist: pypdf<6,>=4; extra == 'dev'
Requires-Dist: pytest-cov<6,>=5.0; extra == 'dev'
Requires-Dist: pytest<9,>=8.0; extra == 'dev'
Requires-Dist: ruff<1,>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# 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

```bash
pip install reportlab-json-renderer
```

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

```bash
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)

```bash
# 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`

```bash
# 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

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

## Quick Start

### Python API

```python
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

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

```python
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`](pdf-generator.md) for the full specification.
See [`docs/json-schema.md`](docs/json-schema.md) for a human-readable field reference.

Minimal example:

```json
{
  "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`](docs/custom-blocks.md).
- **Custom themes**: Create a `Theme` dataclass and register via the theme registry. See [`docs/custom-themes.md`](docs/custom-themes.md).
- **Custom templates**: Create a `Template` dataclass and register via the template registry. See [`docs/custom-templates.md`](docs/custom-templates.md).

## Development

```bash
# 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`](docs/implementation-checklist.md) for the
original build checklist and [`docs/release-readiness-checklist.md`](docs/release-readiness-checklist.md)
for current release work.
