Source code for kstlib.monitoring.renderer
"""Jinja2 rendering integration for monitoring render types.
Provides a Jinja2 filter ``render`` that dispatches to ``Renderable.render()``
for monitoring objects, and HTML-escapes primitives. Includes a pre-configured
environment factory and a standalone template rendering helper.
Examples:
Render a template with monitoring objects:
>>> from kstlib.monitoring.renderer import render_template
>>> from kstlib.monitoring.cell import StatusCell
>>> from kstlib.monitoring.types import StatusLevel
>>> cell = StatusCell("UP", StatusLevel.OK)
>>> html = render_template("<p>{{ s | render }}</p>", {"s": cell})
>>> "status-ok" in html
True
"""
from __future__ import annotations
import html as _html
from typing import Any
from jinja2 import Environment
from markupsafe import Markup
from kstlib.monitoring._styles import get_css_classes
from kstlib.monitoring.types import Renderable
[docs]
def render_html(value: Any, inline_css: bool = False) -> Markup:
"""Jinja2 filter that renders a value as safe HTML.
When *value* implements :class:`~kstlib.monitoring.types.Renderable`,
its ``.render()`` method is called. Otherwise the value is converted
to a string and HTML-escaped.
Register this filter under the name ``render`` on a Jinja2 environment
so templates can use ``{{ data | render }}``.
Args:
value: Any value to render. ``Renderable`` objects are dispatched
to their own ``render()`` method; everything else is escaped.
inline_css: Forwarded to ``Renderable.render(inline_css=...)``.
Returns:
A :class:`jinja2.Markup` instance (marked safe to prevent
double-escaping by Jinja2 autoescape).
Examples:
>>> from kstlib.monitoring.renderer import render_html
>>> str(render_html("<b>bold</b>"))
'<b>bold</b>'
"""
if isinstance(value, Renderable):
return Markup(value.render(inline_css=inline_css))
return Markup(_html.escape(str(value)))
[docs]
def create_environment(**kwargs: Any) -> Environment:
"""Create a Jinja2 :class:`~jinja2.Environment` with monitoring filters.
The returned environment has:
- ``autoescape=True`` by default (overridable via *kwargs*).
- The ``render`` filter bound to :func:`render_html`.
Args:
**kwargs: Forwarded to :class:`jinja2.Environment`. Common
options include ``loader``, ``autoescape``, ``trim_blocks``.
Returns:
A configured :class:`jinja2.Environment`.
Examples:
>>> from kstlib.monitoring.renderer import create_environment
>>> env = create_environment()
>>> "render" in env.filters
True
"""
kwargs.setdefault("autoescape", True)
env = Environment(**kwargs)
env.filters["render"] = render_html
return env
[docs]
def render_template(
source: str,
context: dict[str, Any] | None = None,
*,
inline_css: bool = False,
) -> str:
"""Render a Jinja2 template string with monitoring support.
This is a high-level convenience function that creates a temporary
environment, compiles *source* as a template, and renders it with
*context*.
When ``inline_css=False`` (default), the CSS class definitions from
:func:`~kstlib.monitoring._styles.get_css_classes` are prepended to
the output so that class-based rendering works out of the box.
Args:
source: Jinja2 template source string.
context: Template variables. ``None`` is treated as an empty dict.
inline_css: If ``True``, skip the ``<style>`` block prepend.
Useful when styles are inlined into each element.
Returns:
Rendered HTML string.
Raises:
TypeError: If *source* is not a ``str`` or *context* is not
a ``dict`` (or ``None``).
Examples:
>>> from kstlib.monitoring.renderer import render_template
>>> render_template("Hello {{ name }}", {"name": "World"}, inline_css=True)
'Hello World'
"""
if not isinstance(source, str):
raise TypeError(f"source must be str, got {type(source).__name__}")
if context is not None and not isinstance(context, dict):
raise TypeError(f"context must be dict or None, got {type(context).__name__}")
env = create_environment()
template = env.from_string(source)
rendered = template.render(**(context or {}))
if inline_css:
return rendered
return get_css_classes() + "\n" + rendered
__all__ = [
"create_environment",
"render_html",
"render_template",
]