Composable PDF building blocks (tables, headers, footers, title pages, tile grids) built on ReportLab.
Project description
pdfblox
Composable PDF building blocks for report generation, built on ReportLab. pdfblox turns structured data and images into finished PDF reports — styled tables, page headers/footers, title pages, and tile grids.
Design
pdfblox is the PDF-generation half of a larger report-writing system. It deliberately knows nothing about where data comes from:
┌──────────────────────────────────────────────────────────────┐
│ Integration wrapper (owns .env / parameter injection) │
│ │
│ ┌─────────────────────┐ ┌────────────────────────┐ │
│ │ Data-source library │ data │ pdfblox │ │
│ │ (e.g. Some REST) │ ──────▶ │ (this library) │ │
│ │ fetch + render │ images │ build the PDF │ │
│ └─────────────────────┘ └────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Consequences of this boundary:
- One dependency:
reportlab. Noplotly, nokaleido, no networking. - No
dotenv, noos.getenv. All configuration enters through explicit function arguments and*Configdataclasses. Environment/credential loading belongs to the integration layer above. - Images come in as bytes or flowables. A logo is
logo_data: bytesor alogo_path; a chart is a ready-made ReportLabImage. pdfblox never fetches or renders them.
Documentation
- AI_REPORT_AUTHORING.md — how to author a report with pdfblox (block reference, recipes, pitfalls, a full template). The guide to read when generating report scripts.
- CLAUDE.md — how to develop the library itself (boundary rules, conventions, how to add a block).
Installation
pip install -e .
Building Blocks
| Block | Module | Key API |
|---|---|---|
| Styled table | pdfblox.tables |
ColumnConfig, TableConfig, create_table |
| Grouped (banded) table | pdfblox.tables |
GroupBandConfig, grouped_table |
| Key/value table | pdfblox.tables |
KeyValueConfig, create_keyvalue_table |
| Text & headings | pdfblox.text |
TextConfig, paragraph, heading |
| Lists | pdfblox.lists |
ListConfig, bullet_list, numbered_list |
| Image | pdfblox.images |
make_image |
| Charts (native vector) | pdfblox.charts |
ChartConfig, bar_chart, line_chart, pie_chart, scatter_chart |
| Layout primitives | pdfblox.layout |
spacer, divider, CalloutConfig, kpi_callout, PlaceholderConfig, placeholder_box |
| Page header | pdfblox.header |
HeaderConfig, draw_page_header |
| Page footer | pdfblox.footer |
FooterConfig, draw_page_footer |
| Title / cover page | pdfblox.document |
TitlePageConfig |
| Tile grid | pdfblox.document |
TileGridConfig, build_tile_grid |
| Document assembly | pdfblox.document |
PdfConfig, build_pdf, build_paginated_pdf |
| Fluent builder | pdfblox.report |
Report |
| Theme | pdfblox.theme |
Theme |
| Theme presets | pdfblox.themes |
get_theme, available_themes, corporate_blue, slate_gray, forest_green, burgundy, teal, graphite |
| Unicode fonts | pdfblox.fonts |
use_unicode_fonts, register_font |
| ReportLab value re-exports | pdfblox.primitives |
colors, HexColor, inch, cm, mm, letter, legal, A4, A3, landscape, portrait, PageBreak |
| Date / OS helpers | pdfblox.utils |
parse_timestamp, normalize_date, blank_to_none, open_file_in_windows |
No import reportlab needed: value re-exports
The generic ReportLab values a report reaches for — page sizes, units, and
colours (plus the PageBreak flowable) — are re-exported from pdfblox, so a
report script needs no direct import reportlab:
from pdfblox import letter, landscape, inch, colors, HexColor, PageBreak
PAGE = landscape(letter)
MARGIN = 0.5 * inch
BRAND = HexColor("#1F3864")
GREY = colors.HexColor("#888888")
These are stable value constants, not ReportLab's rendering API. The rendering
API (Table, Flowable, canvas, BaseDocTemplate, …) is intentionally not
re-exported — it's what the blocks encapsulate. If a report genuinely needs one,
importing it from reportlab directly is the explicit, self-documenting escape
hatch.
One palette for the whole report: Theme
A Theme bundles fonts and colours and produces every block's config from
them. Pass it to Report and blocks are styled automatically; explicit
configs and per-call overrides still win.
from pdfblox import Report, Theme, HexColor
theme = Theme(primary_color=HexColor("#7A0019")) # brand colour
(
Report("out.pdf",
theme=theme,
header_config=theme.header_config("Quarterly Report"),
footer_config=theme.footer_config())
.add_heading("Summary") # styled from theme
.add_paragraph("Body text.") # styled from theme
.add_callout("42", "Sensors") # styled from theme
.build()
)
Charts
pdfblox draws native vector charts with ReportLab's own graphics engine —
no Plotly, kaleido, or matplotlib, and no extra dependency. Good for the
standard reporting charts; series colours come from the active Theme.
from pdfblox import Report, get_theme
(
Report("out.pdf", theme=get_theme("forest_green"))
.add_bar_chart([[3, 5, 2], [4, 1, 6]], categories=["A", "B", "C"],
series_names=["Plan", "Actual"])
.add_line_chart([1, 3, 2, 5], categories=["Q1", "Q2", "Q3", "Q4"])
.add_pie_chart([30, 50, 20], labels=["North", "South", "East"], donut=True)
.add_scatter_chart([(1, 2), (3, 4), (5, 3)])
.build()
)
To embed a chart rendered elsewhere (e.g. a Plotly/server figure), render it to
PNG/SVG bytes in the data-source layer and place it with make_image instead —
pdfblox stays rendering-engine-free either way.
Built-in presets
Six ready-made palettes popular for reporting — corporate_blue,
slate_gray, forest_green, burgundy, teal, graphite. Look one up by
name (with optional overrides) or call its factory:
from pdfblox import Report, get_theme, available_themes
print(available_themes()) # list preset names
theme = get_theme("slate_gray", base_font_size=11)
Report("out.pdf", theme=theme,
header_config=theme.header_config("Status Report"),
footer_config=theme.footer_config()).add_heading("Summary").build()
Recommended entry point: the Report builder
from pdfblox import Report, HeaderConfig, FooterConfig
(
Report("out.pdf",
header_config=HeaderConfig(title="Status"),
footer_config=FooterConfig())
.add_heading("Summary")
.add_paragraph("All systems nominal.")
.add_divider()
.add_callout("42", "Active Sensors")
.add_keyvalue_table([("Site", "North"), ("Status", "OK")])
.build()
)
Quick start
A paginated table report with a header and footer — no data source, just inline data:
from pdfblox import (
ColumnConfig, PdfConfig, HeaderConfig, FooterConfig,
build_paginated_pdf, letter, landscape, inch,
)
data = [
{"name": "Sensor A", "value": 12.4, "status": "OK"},
{"name": "Sensor B", "value": 99.1, "status": "ALERT"},
]
columns = [
ColumnConfig("Instrument", 3 * inch, "name", alignment="LEFT"),
ColumnConfig("Reading", 2 * inch, "value", formatter=lambda v: f"{v:.1f}"),
ColumnConfig("Status", 2 * inch, "status"),
]
build_paginated_pdf(
data,
columns,
"report.pdf",
pdf_config=PdfConfig(page_size=landscape(letter)),
header_config=HeaderConfig(title="Instrument Status", company_info=["Acme Co."]),
footer_config=FooterConfig(),
)
For mixed content (charts, paragraphs, custom flowables) use build_pdf; for
a grid of chart tiles use build_tile_grid to produce per-page Table
flowables, then pass them to build_pdf. Add a cover page by passing a
TitlePageConfig.
Tests
pip install -e ".[test]"
pytest
Each building block has a focused test under tests/ that exercises it and,
where relevant, renders a real PDF into a temp directory.
License
MIT — see LICENSE.
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 pdfblox-1.4.0.tar.gz.
File metadata
- Download URL: pdfblox-1.4.0.tar.gz
- Upload date:
- Size: 49.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d85d290fd7c2839d8b9a544d008a2d6f1f071251afd3281c52c512c669903aa3
|
|
| MD5 |
88a637219c5a9cbbd2256c2aa89e2336
|
|
| BLAKE2b-256 |
9af394fe1b7439cd5a9f417d3477183f2f44c1a070770b7dcf09de7615cba725
|
File details
Details for the file pdfblox-1.4.0-py3-none-any.whl.
File metadata
- Download URL: pdfblox-1.4.0-py3-none-any.whl
- Upload date:
- Size: 44.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2822c62dc70138d36654dbb85d53f80ba983d822fc645cb45d5de3178edc35e9
|
|
| MD5 |
d0898157f11709fcd41663da14b1349c
|
|
| BLAKE2b-256 |
0b859c274ef053323f7d89d4d75b36381392654f1072539cf0515eab03f06c7d
|