Source code for smarter.apps.llmtool.extension.docs

"""
Render an extension's documentation, written in reStructuredText, as HTML.

An extension documents itself in its package's module docstring, and optionally in more
pages in its package's ``docs/`` directory (``.rst`` or ``.md``). They are rendered when the
extension is installed, and shown in the admin console.

Documentation comes from the extension's author, so it is rendered safely: raw HTML, file
inclusion and remote images are disabled, and Markdown's raw HTML is escaped.
"""

import html

import markdown
from docutils.core import publish_parts

from smarter.lib import logging
from smarter.lib.django.waffle import SmarterWaffleSwitches

logger = logging.getSmarterLogger(__name__, any_switches=[SmarterWaffleSwitches.EXTENSION_LOGGING])
logger_prefix = logging.formatted_text(__name__)

SAFE_DOCUTILS_SETTINGS = {
    "raw_enabled": False,
    "file_insertion_enabled": False,
    "report_level": 5,
    "halt_level": 5,
    "warning_stream": False,
    "input_encoding": "unicode",
    "output_encoding": "unicode",
    "doctitle_xform": False,
    "initial_header_level": 3,
}


[docs] def render_rst(text: str) -> str: """ Render reStructuredText as an HTML fragment. :param text: The reStructuredText. :returns: The HTML body, or the text in a ``<pre>`` if it cannot be rendered. """ if not text.strip(): return "" try: return publish_parts(source=text, writer="html5", settings_overrides=SAFE_DOCUTILS_SETTINGS)["body"] # docutils raises many kinds of exceptions for malformed input. # pylint: disable=broad-exception-caught except Exception as e: logger.warning("%s.render_rst() could not render reStructuredText: %s", logger_prefix, e) return f"<pre>{html.escape(text)}</pre>"
[docs] def render_markdown(text: str) -> str: """ Render Markdown as an HTML fragment, with any raw HTML escaped. :param text: The Markdown. :returns: The HTML. """ return markdown.markdown(html.escape(text, quote=False), extensions=["fenced_code", "tables"])
[docs] def render_page(filename: str, text: str) -> str: """ Render one documentation page, by its file extension. :param filename: e.g. ``usage.rst`` or ``usage.md``. :param text: The page's text. :returns: The HTML. """ if filename.lower().endswith(".md"): return render_markdown(text) return render_rst(text)
__all__ = ["render_markdown", "render_page", "render_rst"]