Skip to content

htmy.md.core

MD

Bases: Snippet

Component for reading, customizing, and rendering markdown documents.

It supports all the processing utilities of Snippet, including text_resolver and text_processor for formatting, token replacement, and slot conversion to components.

One note regaring slot convesion (text_resolver): it is executed before markdown parsing, and all string segments of the resulting component sequence are parsed individually by the markdown parser. As a consequence, you should only use slots in places where the preceding and following texts individually result in valid markdown.

Source code in htmy/md/core.py
class MD(Snippet):
    """
    Component for reading, customizing, and rendering markdown documents.

    It supports all the processing utilities of `Snippet`, including `text_resolver` and
    `text_processor` for formatting, token replacement, and slot conversion to components.

    One note regaring slot convesion (`text_resolver`): it is executed before markdown parsing,
    and all string segments of the resulting component sequence are parsed individually by the
    markdown parser. As a consequence, you should only use slots in places where the preceding
    and following texts individually result in valid markdown.
    """

    __slots__ = (
        "_converter",
        "_renderer",
    )

    def __init__(
        self,
        path_or_text: Text | str | Path,
        text_resolver: TextResolver | None = None,
        *,
        converter: Callable[[str], Component] | None = None,
        renderer: MarkdownRenderFunction | None = None,
        text_processor: TextProcessor | None = None,
    ) -> None:
        """
        Initialization.

        Arguments:
            path_or_text: The path where the markdown file is located or a markdown `Text`.
            text_resolver: An optional `TextResolver` (e.g. `Slots`) that converts the processed
                text into a component.
            converter: Function that converts an HTML string (the parsed and processed markdown text)
                into a component.
            renderer: Function that gets the parsed and converted content and the metadata (if it exists)
                and turns them into a component.
            text_processor: An optional text processors that can be used to process the text
                content before rendering. It can be used for example for token replacement or
                string formatting.
        """
        super().__init__(path_or_text, text_resolver, text_processor=text_processor)
        self._converter: Callable[[str], Component] = SafeStr if converter is None else converter
        self._renderer = renderer

    def _render_text(self, text: str, context: Context) -> Component:
        md = MarkdownParser.from_context(context, MarkdownParser.default()).parse(text)
        result = self._converter(md["content"])
        return result if self._renderer is None else self._renderer(result, md.get("metadata", None))

__init__(path_or_text, text_resolver=None, *, converter=None, renderer=None, text_processor=None)

Initialization.

Parameters:

Name Type Description Default
path_or_text Text | str | Path

The path where the markdown file is located or a markdown Text.

required
text_resolver TextResolver | None

An optional TextResolver (e.g. Slots) that converts the processed text into a component.

None
converter Callable[[str], Component] | None

Function that converts an HTML string (the parsed and processed markdown text) into a component.

None
renderer MarkdownRenderFunction | None

Function that gets the parsed and converted content and the metadata (if it exists) and turns them into a component.

None
text_processor TextProcessor | None

An optional text processors that can be used to process the text content before rendering. It can be used for example for token replacement or string formatting.

None
Source code in htmy/md/core.py
def __init__(
    self,
    path_or_text: Text | str | Path,
    text_resolver: TextResolver | None = None,
    *,
    converter: Callable[[str], Component] | None = None,
    renderer: MarkdownRenderFunction | None = None,
    text_processor: TextProcessor | None = None,
) -> None:
    """
    Initialization.

    Arguments:
        path_or_text: The path where the markdown file is located or a markdown `Text`.
        text_resolver: An optional `TextResolver` (e.g. `Slots`) that converts the processed
            text into a component.
        converter: Function that converts an HTML string (the parsed and processed markdown text)
            into a component.
        renderer: Function that gets the parsed and converted content and the metadata (if it exists)
            and turns them into a component.
        text_processor: An optional text processors that can be used to process the text
            content before rendering. It can be used for example for token replacement or
            string formatting.
    """
    super().__init__(path_or_text, text_resolver, text_processor=text_processor)
    self._converter: Callable[[str], Component] = SafeStr if converter is None else converter
    self._renderer = renderer

MarkdownParser

Bases: ContextAware

Context-aware markdown parser.

By default, this class uses the markdown library with a sensible set of extensions including code highlighing.

Source code in htmy/md/core.py
class MarkdownParser(ContextAware):
    """
    Context-aware markdown parser.

    By default, this class uses the `markdown` library with a sensible set of
    [extensions](https://python-markdown.github.io/extensions/) including code highlighing.
    """

    __slots__ = ("_md",)

    _default: ClassVar[MarkdownParser | None] = None
    """The default instance or `None` if one hasn't been created already."""

    @classmethod
    def default(cls) -> MarkdownParser:
        """
        Returns the default instance.
        """
        if cls._default is None:
            cls._default = MarkdownParser()

        return cls._default

    def __init__(self, md: MarkdownParserFunction | None = None) -> None:
        """
        Initialization.

        Arguments:
            md: The parser function to use.
        """
        super().__init__()
        self._md = md

    def parse(self, text: str) -> ParsedMarkdown:
        """
        Returns the markdown data by parsing the given text.
        """
        md = self._md
        if md is None:
            md = self._default_md()
            self._md = md

        return md(text)

    def _default_md(self) -> MarkdownParserFunction:
        """
        Function that creates the default markdown parser.

        Returns:
            The default parser function.
        """
        md = Markdown(extensions=("extra", "meta", "codehilite"))

        def parse(text: str) -> ParsedMarkdown:
            md.reset()
            parsed = md.convert(text)
            return {"content": parsed, "metadata": getattr(md, "Meta", None)}

        return parse

_default = None class-attribute

The default instance or None if one hasn't been created already.

__init__(md=None)

Initialization.

Parameters:

Name Type Description Default
md MarkdownParserFunction | None

The parser function to use.

None
Source code in htmy/md/core.py
def __init__(self, md: MarkdownParserFunction | None = None) -> None:
    """
    Initialization.

    Arguments:
        md: The parser function to use.
    """
    super().__init__()
    self._md = md

_default_md()

Function that creates the default markdown parser.

Returns:

Type Description
MarkdownParserFunction

The default parser function.

Source code in htmy/md/core.py
def _default_md(self) -> MarkdownParserFunction:
    """
    Function that creates the default markdown parser.

    Returns:
        The default parser function.
    """
    md = Markdown(extensions=("extra", "meta", "codehilite"))

    def parse(text: str) -> ParsedMarkdown:
        md.reset()
        parsed = md.convert(text)
        return {"content": parsed, "metadata": getattr(md, "Meta", None)}

    return parse

default() classmethod

Returns the default instance.

Source code in htmy/md/core.py
@classmethod
def default(cls) -> MarkdownParser:
    """
    Returns the default instance.
    """
    if cls._default is None:
        cls._default = MarkdownParser()

    return cls._default

parse(text)

Returns the markdown data by parsing the given text.

Source code in htmy/md/core.py
def parse(self, text: str) -> ParsedMarkdown:
    """
    Returns the markdown data by parsing the given text.
    """
    md = self._md
    if md is None:
        md = self._default_md()
        self._md = md

    return md(text)

htmy.md.typing

MarkdownParserFunction = Callable[[str], ParsedMarkdown] module-attribute

Callable that converts a markdown string into a ParsedMarkdown object.

MarkdownRenderFunction = Callable[[Component, MarkdownMetadataDict | None], Component] module-attribute

Renderer function definition for markdown data.

ParsedMarkdown

Bases: TypedDict

Type definition for parsed markdown data.

Source code in htmy/md/typing.py
class ParsedMarkdown(TypedDict):
    """Type definition for parsed markdown data."""

    content: str
    metadata: NotRequired[MarkdownMetadataDict | None]