dashboard: Show module and class docstrings

This commit is contained in:
Valentin Lorentz 2022-04-10 14:53:17 +02:00
parent a3f0d42248
commit 358b6c2213

View File

@ -2,6 +2,7 @@ import base64
import dataclasses import dataclasses
import gzip import gzip
import hashlib import hashlib
import importlib
from pathlib import Path from pathlib import Path
import re import re
import sys import sys
@ -16,10 +17,10 @@ from typing import (
Tuple, Tuple,
TypeVar, TypeVar,
) )
import xml.dom.minidom
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from defusedxml.ElementTree import parse as parse_xml from defusedxml.ElementTree import parse as parse_xml
import docutils.core
NETLIFY_CHAR_BLACKLIST = frozenset('":<>|*?\r\n#') NETLIFY_CHAR_BLACKLIST = frozenset('":<>|*?\r\n#')
"""Characters not allowed in output filenames""" """Characters not allowed in output filenames"""
@ -117,9 +118,24 @@ def iter_job_results(job_file_name: Path, job: ET.ElementTree) -> Iterator[CaseR
) )
def rst_to_element(s: str) -> ET.Element:
html = docutils.core.publish_parts(s, writer_name="xhtml")["html_body"]
htmltree = ET.fromstring(html)
return htmltree
def append_docstring(element: ET.Element, obj: object) -> None:
if obj.__doc__ is None:
return
element.append(rst_to_element(obj.__doc__))
def build_module_html( def build_module_html(
jobs: List[str], results: List[CaseResult], module_name: str jobs: List[str], results: List[CaseResult], module_name: str
) -> ET.Element: ) -> ET.Element:
module = importlib.import_module(module_name)
root = ET.Element("html") root = ET.Element("html")
head = ET.SubElement(root, "head") head = ET.SubElement(root, "head")
ET.SubElement(head, "title").text = module_name ET.SubElement(head, "title").text = module_name
@ -129,6 +145,8 @@ def build_module_html(
ET.SubElement(body, "h1").text = module_name ET.SubElement(body, "h1").text = module_name
append_docstring(body, module)
results_by_class = group_by(results, lambda r: r.class_name) results_by_class = group_by(results, lambda r: r.class_name)
table = ET.SubElement(body, "table") table = ET.SubElement(body, "table")
@ -153,6 +171,7 @@ def build_module_html(
id=row_anchor, id=row_anchor,
) )
section_header.text = class_name section_header.text = class_name
append_docstring(th, getattr(module, class_name))
# Header row: one column for each implementation # Header row: one column for each implementation
table.append(job_row) table.append(job_row)
@ -213,10 +232,6 @@ def build_module_html(
else: else:
cell.text = text or "?" cell.text = text or "?"
# Hacky: ET expects the namespace to be present in every tag we create instead;
# but it would be excessively verbose.
root.set("xmlns", "http://www.w3.org/1999/xhtml")
return root return root
@ -261,13 +276,14 @@ def write_html_index(output_dir: Path, pages: List[Tuple[str, str]]) -> None:
ET.SubElement(body, "h1").text = "irctest dashboard" ET.SubElement(body, "h1").text = "irctest dashboard"
ul = ET.SubElement(body, "ul") dl = ET.SubElement(body, "dl")
for (module_name, file_name) in sorted(pages): for (module_name, file_name) in sorted(pages):
link = ET.SubElement(ET.SubElement(ul, "li"), "a", href=f"./{file_name}") module = importlib.import_module(module_name)
link.text = module_name
root.set("xmlns", "http://www.w3.org/1999/xhtml") link = ET.SubElement(ET.SubElement(dl, "dt"), "a", href=f"./{file_name}")
link.text = module_name
append_docstring(ET.SubElement(dl, "dd"), module)
write_xml_file(output_dir / "index.xhtml", root) write_xml_file(output_dir / "index.xhtml", root)
@ -281,14 +297,15 @@ def write_assets(output_dir: Path) -> None:
def write_xml_file(filename: Path, root: ET.Element) -> None: def write_xml_file(filename: Path, root: ET.Element) -> None:
# Hacky: ET expects the namespace to be present in every tag we create instead;
# but it would be excessively verbose.
root.set("xmlns", "http://www.w3.org/1999/xhtml")
# Serialize # Serialize
s = ET.tostring(root) s = ET.tostring(root)
# Prettify with filename.open("wb") as fd:
s = xml.dom.minidom.parseString(s).toprettyxml(indent=" ") fd.write(s)
with filename.open("wt") as fd:
fd.write(s) # type: ignore
def parse_xml_file(filename: Path) -> ET.ElementTree: def parse_xml_file(filename: Path) -> ET.ElementTree: