Implement HTML renderer with Jinja2
This commit is contained in:
5
src/py_dvt_ate/reporting/renderers/__init__.py
Normal file
5
src/py_dvt_ate/reporting/renderers/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
"""Report renderers for HTML and PDF output."""
|
||||||
|
|
||||||
|
from py_dvt_ate.reporting.renderers.html import HTMLRenderer
|
||||||
|
|
||||||
|
__all__ = ["HTMLRenderer"]
|
||||||
100
src/py_dvt_ate/reporting/renderers/html.py
Normal file
100
src/py_dvt_ate/reporting/renderers/html.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
"""HTML renderer using Jinja2 templates.
|
||||||
|
|
||||||
|
This module provides HTML rendering for test reports using Jinja2 templating.
|
||||||
|
Templates are loaded from the package's templates directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from importlib import resources
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||||
|
|
||||||
|
from py_dvt_ate import __version__
|
||||||
|
from py_dvt_ate.reporting.exceptions import TemplateRenderError
|
||||||
|
from py_dvt_ate.reporting.models import ReportData
|
||||||
|
|
||||||
|
|
||||||
|
class HTMLRenderer:
|
||||||
|
"""Renders HTML reports from ReportData using Jinja2 templates.
|
||||||
|
|
||||||
|
The renderer loads templates from the py_dvt_ate.reporting.templates package
|
||||||
|
and provides methods for rendering complete HTML reports.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""Initialise the HTML renderer with Jinja2 environment."""
|
||||||
|
self._env = Environment(
|
||||||
|
loader=PackageLoader("py_dvt_ate.reporting", "templates"),
|
||||||
|
autoescape=select_autoescape(["html", "xml"]),
|
||||||
|
)
|
||||||
|
self._css_content: str | None = None
|
||||||
|
|
||||||
|
def _load_css(self) -> str:
|
||||||
|
"""Load CSS content from the templates directory."""
|
||||||
|
if self._css_content is None:
|
||||||
|
templates_pkg = resources.files("py_dvt_ate.reporting.templates")
|
||||||
|
css_file = templates_pkg.joinpath("styles.css")
|
||||||
|
self._css_content = css_file.read_text()
|
||||||
|
return self._css_content
|
||||||
|
|
||||||
|
def _load_logo(self, logo_path: Path | None) -> str | None:
|
||||||
|
"""Load and encode logo image as base64.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
logo_path: Path to logo image file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Base64-encoded image data, or None if no logo or file not found.
|
||||||
|
"""
|
||||||
|
if logo_path is None or not logo_path.exists():
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with logo_path.open("rb") as f:
|
||||||
|
return base64.b64encode(f.read()).decode("utf-8")
|
||||||
|
except OSError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def render(self, data: ReportData) -> str:
|
||||||
|
"""Render a test report to HTML.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: Report data containing test run, results, and charts.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Complete HTML document as a string.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TemplateRenderError: If template rendering fails.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
template = self._env.get_template("test_report.html")
|
||||||
|
|
||||||
|
# Format config JSON for display
|
||||||
|
config_formatted = ""
|
||||||
|
if data.run.config_json:
|
||||||
|
try:
|
||||||
|
config_dict = json.loads(data.run.config_json)
|
||||||
|
config_formatted = json.dumps(config_dict, indent=2)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
config_formatted = data.run.config_json
|
||||||
|
|
||||||
|
# Prepare template context
|
||||||
|
context = {
|
||||||
|
"data": data,
|
||||||
|
"css_content": self._load_css(),
|
||||||
|
"logo_base64": self._load_logo(data.config.logo_path),
|
||||||
|
"company_name": data.config.company_name,
|
||||||
|
"version": __version__,
|
||||||
|
"generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
"config_formatted": config_formatted,
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.render(**context)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
msg = f"Failed to render HTML template: {e}"
|
||||||
|
raise TemplateRenderError(msg) from e
|
||||||
Reference in New Issue
Block a user