Source code for httk.web.renderers.rst

from pathlib import Path
from typing import Any

from docutils import io, nodes
from docutils.core import publish_programmatically
from docutils.writers.html5_polyglot import Writer

from .base import RenderResult

_RST_SETTINGS_OVERRIDES = {
    "raw_enabled": False,
    "file_insertion_enabled": False,
}


[docs] class RstRenderer:
[docs] def render(self, source_path: Path) -> RenderResult: source = source_path.read_text(encoding="utf-8") # docutils' own type hints for publish_programmatically are narrower than # its documented runtime contract (e.g. writer_name/config_section accept # None when a writer instance is supplied, and source_class accepts any # Input subclass). Pass the arguments through an Any-typed mapping so the # call reflects the real API without per-argument casts. publish_kwargs: dict[str, Any] = { "source_class": io.StringInput, "source": source, "source_path": str(source_path), "destination_class": io.StringOutput, "destination": None, "destination_path": None, "reader": None, "reader_name": "standalone", "parser": None, "parser_name": "restructuredtext", "writer": Writer(), "writer_name": None, "settings": None, "settings_spec": None, "settings_overrides": _RST_SETTINGS_OVERRIDES, "config_section": None, "enable_exit_status": False, } _, pub = publish_programmatically(**publish_kwargs) html = pub.writer.parts.get("html_body", "") document = pub.document assert document is not None metadata = self._extract_metadata(document) return RenderResult(html=html, metadata=metadata)
def _extract_metadata(self, doctree: nodes.document) -> dict[str, object]: metadata: dict[str, object] = {} for field in doctree.findall(nodes.field): if len(field.children) < 2: continue name_node = field.children[0] body_node = field.children[1] name = name_node.astext().strip().lower() if name.endswith("-list"): key = name[: -len("-list")] values: list[str] = [] for item in body_node.findall(nodes.list_item): text = item.astext().strip() if text: values.append(text) if not values: text = body_node.astext().strip() values = [x.strip() for x in text.splitlines() if x.strip()] metadata[key] = values else: metadata[name] = body_node.astext().strip() return metadata