Source code for moptipy.utils.html

"""The HTML text format driver."""

from io import TextIOBase
from typing import Final

from moptipy.utils.formatted_string import (
    NAN,
    NEGATIVE_INFINITY,
    NUMBER,
    POSITIVE_INFINITY,
    SPECIAL,
    TEXT,
)
from moptipy.utils.text_format import MODE_TABLE_HEADER, TextFormatDriver

#: the default border style
_BORDER: Final[str] = "1pt solid black"

#: special characters in HTML
SPECIAL_CHARS: Final[dict[str, str]] = {
    "\u2205": "∅",
    "\u221E": "∞",
    "-\u221E": "-∞",
    "inf": "∞",
    "-inf": "-∞",
    "nan": "∅",
    "\u03b1": "α",
    "\u2014": "—",
}


[docs] class HTML(TextFormatDriver): """The HTML text driver."""
[docs] def begin_table_body(self, stream: TextIOBase, cols: str) -> None: """Write the beginning of the table body.""" stream.write( f'<table style="border:{_BORDER};border-collapse:collapse">')
[docs] def end_table_body(self, stream: TextIOBase, cols: str) -> None: """Write the ending of the table body.""" stream.write("</tbody></table>")
[docs] def begin_table_header(self, stream: TextIOBase, cols: str) -> None: """Begin the header of an HTML table.""" stream.write("<thead>")
[docs] def end_table_header(self, stream: TextIOBase, cols: str) -> None: """End the header of an HTML table.""" stream.write("</thead><tbody>")
[docs] def begin_table_row(self, stream: TextIOBase, cols: str, section_index: int, row_index: int, row_mode: int) -> None: """Begin a row in an HTML table.""" stream.write("<tr>")
[docs] def end_table_row(self, stream: TextIOBase, cols: str, section_index: int, row_index: int) -> None: """End a row in a HTML table.""" stream.write("</tr>")
[docs] def begin_table_cell(self, stream: TextIOBase, cols: str, section_index: int, row_index: int, col_index: int, cell_mode: int) -> None: """Begin an HTML table cell.""" style: str = cols[col_index] style = "center" if style == "c" \ else "left" if style == "l" else "right" style = f"padding:3pt;text-align:{style}" if col_index < (len(cols) - 1): style = f"{style};border-right:{_BORDER}" if row_index <= 0 <= section_index: style = f"{style};border-top:{_BORDER}" cell: str = "th" if (cell_mode == MODE_TABLE_HEADER) else "td" stream.write(f'<{cell} style="{style}">') # noqa: B028
[docs] def end_table_cell(self, stream: TextIOBase, cols: str, section_index: int, row_index: int, col_index: int, cell_mode: int) -> None: """End an HTML table cell.""" stream.write("</th>" if (cell_mode == MODE_TABLE_HEADER) else "</td>")
[docs] def text(self, stream: TextIOBase, text: str, bold: bool, italic: bool, code: bool, mode: int) -> None: """Print a text string.""" if len(text) <= 0: return styles: str = "" if bold: styles = "font-weight:bold;" if italic: styles += "font-style:italic;" if code: styles += "font-family:monospace;" if len(styles) > 0: stream.write(f'<span style="{styles[0:-1]}">') # noqa: B028 if mode == TEXT: stream.write(text) elif mode == NUMBER: i: int = text.find("e") if i < 0: i = text.find("E") if i > 0: stream.write(f"{text[:i]}&#xD7;10<sup>{text[i + 1:]}</sup>") else: stream.write(text) elif mode == NAN: stream.write("&#x2205;") elif mode == POSITIVE_INFINITY: stream.write("&#x221E;") elif mode == NEGATIVE_INFINITY: stream.write("-&#x221E;") elif mode == SPECIAL: s: Final[str] = str(text) if s not in SPECIAL_CHARS: raise ValueError(f"invalid special character: {s!r}") stream.write(SPECIAL_CHARS[s]) else: raise ValueError(f"invalid mode {mode} for text {text!r}.") if len(styles) > 0: stream.write("</span>")
def __str__(self): """ Get the appropriate file suffix. :returns: the file suffix :retval 'html': always """ return "html"
[docs] @staticmethod def instance() -> "HTML": """ Get the HTML format singleton instance. :returns: the singleton instance of the HTML format """ attr: Final[str] = "_instance" func: Final = HTML.instance if not hasattr(func, attr): setattr(func, attr, HTML()) return getattr(func, attr)