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.
Installation
pip install pdfblox
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 |
| Drawing (bespoke vector art) | pdfblox.drawing |
DrawingConfig, vector_drawing + shapes (Circle, Ellipse, Polygon, Line, Path, …) |
| Overlays (anchored / page placement) | pdfblox.overlay |
Overlay, watermark, text_drawing |
| 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()
Drawing (bespoke vector art)
When a report needs a custom mark the other blocks don't cover — an emblem,
logo, badge, or decorative shape — vector_drawing wraps ReportLab graphics
shapes into a placeable Drawing flowable. The shape vocabulary is re-exported,
so there's still no direct import reportlab:
from pdfblox import Report, vector_drawing, DrawingConfig, Circle, Polygon, HexColor
emblem = vector_drawing(
[Circle(20, 20, 18, fillColor=HexColor("#F4C20D"), strokeColor=None),
Polygon(points=[36, 22, 50, 20, 36, 16], fillColor=HexColor("#E8740C"))],
DrawingConfig(width=52, height=40),
)
Report("out.pdf").add_heading("Brand").add_drawing(emblem).build()
shapes may also be a build(width, height) -> shapes callable when geometry
depends on the drawing size. For data-driven vectors use the chart blocks
above; for a finely detailed or photographic logo, prefer make_image.
Overlays (watermarks, emblems, page stamps)
Blocks place content in the flow — top-to-bottom in reading order. An
overlay pins the same vector Drawing to a fixed spot on chosen pages,
on top of the content: watermarks, corner emblems, "CONFIDENTIAL" stamps.
Placement is anchor-first ("top-left" … "center" … "bottom-right"), with
raw xy=(x, y) as an escape hatch; pages selects "all", "first",
"last", an int/list of page numbers, or a callable(page, total).
from pdfblox import Report, watermark, vector_drawing, DrawingConfig, Circle, HexColor
emblem = vector_drawing([Circle(20, 20, 18, fillColor=HexColor("#F4C20D"))],
DrawingConfig(width=40, height=40))
(
Report("out.pdf")
.add_heading("Quarterly Report")
.add_paragraph("…")
.add_watermark("DRAFT") # faint, 45°, every page
.add_overlay(emblem, anchor="top-right", pages="first") # emblem on page 1
.build()
)
Same Drawing, two placement models — pick by where it belongs:
| You want… | Use |
|---|---|
| A drawing in the content stream (reading order, flows, page-breaks) | add_drawing (flow) |
| A drawing pinned to the page (watermark, corner mark, stamp; may repeat) | add_overlay |
Overlays render on top with optional opacity (the watermark look) and
rotation. Page numbers are absolute — a cover/title page counts as page 1.
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.
License
Licensed under the MIT 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.6.1.tar.gz.
File metadata
- Download URL: pdfblox-1.6.1.tar.gz
- Upload date:
- Size: 59.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6967d95b51fd4c9c5ec4ee608a2496839626287e5a1c7d03dd310f057d0538be
|
|
| MD5 |
6a64c19757fb71522c14b03b1cf373de
|
|
| BLAKE2b-256 |
e08aff9cb0c63a810dcc17df0d477296c746d7ee5b07c95e525a553790bb7019
|
File details
Details for the file pdfblox-1.6.1-py3-none-any.whl.
File metadata
- Download URL: pdfblox-1.6.1-py3-none-any.whl
- Upload date:
- Size: 52.5 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 |
a12457774bbb7a1188cec2e41ef61b84a0fe1060368ab9eec074ca968a4319cf
|
|
| MD5 |
d8fecae261bc067563a904e21c36e29c
|
|
| BLAKE2b-256 |
4561a0ce9f5ed61f2144c5e43e33576db2bbbdfb9acdadd4e21ced22ed02824c
|