Source code for timApp.markdown.dumboclient

"""Defines a client interface for using Dumbo, the markdown converter."""
import json
from enum import Enum
from typing import Union, NamedTuple, Optional, overload

import requests

from timApp.document.timjsonencoder import TimJsonEncoder


[docs]class DumboHTMLException(Exception): code = 400 description = ""
[docs]class MathType(Enum): SVG = "svg" MathJax = "mathjax" PNG = "png"
[docs] @staticmethod def from_string(s: str): try: return MathType(s) except ValueError: return MathType.MathJax
[docs]class InputFormat(Enum): CommonMark = "commonmark" GitHubMarkdown = "gfm" Markdown = "markdown" MarkdownStrict = "markdown_strict" MediaWiki = "mediawiki" RST = "rst" LaTeX = "latex"
[docs] @staticmethod def from_string(s: str): try: return InputFormat(s) except ValueError: return InputFormat.Markdown
[docs]class DumboOptions(NamedTuple): math_type: MathType math_preamble: str input_format: InputFormat smart_punct: bool
[docs] @staticmethod def default(): return DumboOptions( math_type=MathType.MathJax, math_preamble="", input_format=InputFormat.Markdown, smart_punct=False, )
[docs] def dict(self): return { "mathOption": self.math_type.value, "mathPreamble": self.math_preamble, "inputFormat": self.input_format.value, "smartPunct": self.smart_punct, }
DUMBO_URL = "http://dumbo:5000" KEYS_PATHS = {"/mdkeys", "/latexkeys"} @overload def call_dumbo( data: list[str], path="", options: DumboOptions = DumboOptions.default(), data_opts: list[DumboOptions] | None = None, ) -> list[str]: ... @overload def call_dumbo( data: dict, path="", options: DumboOptions = DumboOptions.default(), data_opts: list[DumboOptions] | None = None, ) -> dict: ... @overload def call_dumbo( data: list[dict], path="", options: DumboOptions = DumboOptions.default(), data_opts: list[DumboOptions] | None = None, ) -> list[dict]: ...
[docs]def call_dumbo( data: list[str] | dict | list[dict], path="", options: DumboOptions = DumboOptions.default(), data_opts: list[DumboOptions] | None = None, ) -> list[str] | dict | list[dict]: """Calls Dumbo for converting the given markdown to HTML. :param options: Options for Dumbo. :param data: The data to be converted. :param path: The path of the request. Valid paths are: '', '/', '/mdkeys' and '/markdown' (same as '/' and ''). If path is '/mdkeys', data is expected to be a Dict or List[Dict]. Any dict value that begins with 'md:' is interpreted as Pandoc markdown and is converted to HTML. Otherwise the value is unchanged. The return value format will be the same as input. Otherwise, data is expected to be a List[str]. Each string is interpreted as Pandoc markdown and is converted to HTML. The return value format will be the same as input. """ is_dict = isinstance(data, dict) opts = options.dict() try: if path in KEYS_PATHS: if is_dict: data_to_send = {"content": [{"content": data}], **opts} else: if data_opts: data_to_send = { "content": [ {"content": d, **o.dict()} for d, o in zip(data, data_opts) ], **opts, } else: data_to_send = {"content": [{"content": d} for d in data], **opts} else: data_to_send = {"content": data, **opts} r = requests.post( url=DUMBO_URL + path, data=json.dumps(data_to_send, cls=TimJsonEncoder) ) r.encoding = "utf-8" except requests.ConnectionError: raise Exception("Failed to connect to Dumbo") if r.status_code != 200: raise DumboHTMLException() returned = r.json() if is_dict: return returned[0] else: return returned