z3c.rml - Alternative implementation of RML

raw JSON →
5.0.1 verified Fri May 01 auth: no python

An alternative implementation of Report Markup Language (RML) for generating PDFs. Provides a Pythonic API to produce RML XML that can be rendered by ReportLab. Current version 5.0.1, requires Python >=3.9. Maintained by the Zope Foundation with a slow release cadence.

pip install z3c-rml
error AttributeError: module 'z3c.rml' has no attribute 'story'
cause Incorrect import. The library is structured so that `z3c.rml` is a namespace package; you must import submodules explicitly.
fix
Use from z3c.rml import story instead of import z3c.rml.story.
error ImportError: cannot import name 'RML2PDF' from 'z3c.rml'
cause Trying to import the old class directly from the package root. In modern versions, use `from z3c.rml import rml2pdf`.
fix
Replace from z3c.rml import RML2PDF with from z3c.rml import rml2pdf.
error TypeError: go() takes at least 2 positional arguments (0 given)
cause Calling `rml2pdf.go()` without arguments or with incorrect arguments. The function expects a doc and an output.
fix
Correct usage: rml2pdf.go(doc, output) where doc is a story.DocTemplate and output is a file path or BytesIO.
gotcha z3c.rml uses a Pythonic object model, not raw RML XML. Do not try to pass raw RML strings; use the story objects.
fix Use `z3c.rml.story` classes (DocTemplate, Paragraph, etc.) instead of manually constructing XML.
deprecated The old `z3c.rml.rml2pdf` module had different function signatures. In version 5.0, the preferred method is `rml2pdf.go(doc, output)`. The old direct class instantiation may still work but is not recommended.
fix Use `from z3c.rml import rml2pdf; rml2pdf.go(doc, output)`.
gotcha The library expects a `BytesIO` or a file path for output. Passing a string path works, but avoid passing a file-like object that is not seekable.
fix Ensure output is a writable bytes buffer or a string path to a file.

Minimal example: create a document, add a paragraph, and render to PDF.

from z3c.rml import rml2pdf, story
from io import BytesIO

# Create a simple RML document (this is a Pythonic representation, not raw XML)
doc = story.DocTemplate(
    pagesize=(595.27, 841.89),  # A4
    title="Hello World"
)
story = doc.story
story.append(story.Paragraph("Hello, World!", style=story.ParagraphStyle(name='Normal')))

# Generate PDF
buf = BytesIO()
rml2pdf.go(doc, buf)
buf.seek(0)
print("PDF generated, size:", len(buf.read()))