Implement PDF renderer with WeasyPrint
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
"""Report renderers for HTML and PDF output."""
|
"""Report renderers for HTML and PDF output."""
|
||||||
|
|
||||||
from py_dvt_ate.reporting.renderers.html import HTMLRenderer
|
from py_dvt_ate.reporting.renderers.html import HTMLRenderer
|
||||||
|
from py_dvt_ate.reporting.renderers.pdf import PDFRenderer
|
||||||
|
|
||||||
__all__ = ["HTMLRenderer"]
|
__all__ = ["HTMLRenderer", "PDFRenderer"]
|
||||||
|
|||||||
83
src/py_dvt_ate/reporting/renderers/pdf.py
Normal file
83
src/py_dvt_ate/reporting/renderers/pdf.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
"""PDF renderer using WeasyPrint.
|
||||||
|
|
||||||
|
This module provides PDF rendering from HTML content using WeasyPrint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from py_dvt_ate.reporting.exceptions import PDFConversionError
|
||||||
|
|
||||||
|
|
||||||
|
class PDFRenderer:
|
||||||
|
"""Renders PDF documents from HTML content using WeasyPrint.
|
||||||
|
|
||||||
|
WeasyPrint converts HTML/CSS to PDF with support for page layout,
|
||||||
|
headers/footers, and professional typography.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""Initialise the PDF renderer."""
|
||||||
|
self._weasyprint: type | None = None
|
||||||
|
|
||||||
|
def _get_weasyprint(self) -> type:
|
||||||
|
"""Lazy-load WeasyPrint to avoid import errors when not installed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The WeasyPrint HTML class.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PDFConversionError: If WeasyPrint is not installed.
|
||||||
|
"""
|
||||||
|
if self._weasyprint is None:
|
||||||
|
try:
|
||||||
|
from weasyprint import HTML
|
||||||
|
|
||||||
|
self._weasyprint = HTML
|
||||||
|
except ImportError as e:
|
||||||
|
msg = (
|
||||||
|
"WeasyPrint is required for PDF generation. "
|
||||||
|
"Install it with: pip install py_dvt_ate[reports]"
|
||||||
|
)
|
||||||
|
raise PDFConversionError(msg) from e
|
||||||
|
return self._weasyprint
|
||||||
|
|
||||||
|
def render_to_file(self, html: str, path: Path) -> None:
|
||||||
|
"""Render HTML content to a PDF file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
html: HTML content to convert.
|
||||||
|
path: Output path for the PDF file.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PDFConversionError: If PDF conversion fails.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
HTML = self._get_weasyprint()
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
HTML(string=html).write_pdf(path)
|
||||||
|
except PDFConversionError:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
msg = f"Failed to convert HTML to PDF: {e}"
|
||||||
|
raise PDFConversionError(msg) from e
|
||||||
|
|
||||||
|
def render_to_bytes(self, html: str) -> bytes:
|
||||||
|
"""Render HTML content to PDF bytes.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
html: HTML content to convert.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PDF document as bytes.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PDFConversionError: If PDF conversion fails.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
HTML = self._get_weasyprint()
|
||||||
|
return HTML(string=html).write_pdf()
|
||||||
|
except PDFConversionError:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
msg = f"Failed to convert HTML to PDF: {e}"
|
||||||
|
raise PDFConversionError(msg) from e
|
||||||
Reference in New Issue
Block a user