API Reference

Functions, classes, and modules

6 min read 1149 words

Core API for parsing and rendering Markdown.

High-Level API

parse()

Parse Markdown source into a typed AST.

def parse(
    source: str,
    *,
    source_file: str | None = None,
    directive_registry: DirectiveRegistry | None = None,
    cache: ParseCache | None = None,
) -> Document

Parameters:

  • source: Markdown source text
  • source_file: Optional source file path for error messages
  • directive_registry: Custom directive registry (uses defaults if None)
  • cache: Optional content-addressed parse cache (see Parse Cache)

Returns: Document AST root node

Example:

from patitas import parse

doc = parse("# Hello **World**")
print(doc.children[0])  # Heading(level=1, ...)

# With parse cache (faster incremental builds)
from patitas import parse, DictParseCache
cache = DictParseCache()
doc1 = parse("# Hello", cache=cache)
doc2 = parse("# Hello", cache=cache)  # Cache hit, no re-parse

render()

Render a Patitas AST to HTML.

def render(
    doc: Document,
    *,
    source: str = "",
    highlight: bool = False,
    directive_registry: DirectiveRegistry | None = None,
) -> str

Parameters:

  • doc: Document AST to render
  • source: Original Markdown source for zero-copy extraction
  • highlight: Enable syntax highlighting for code blocks
  • directive_registry: Custom directive registry for rendering

Returns: Rendered HTML string

Example:

from patitas import parse, render

doc = parse("# Hello")
html = render(doc, source="# Hello")
print(html)  # <h1>Hello</h1>

parse_notebook()

Parse a Jupyter notebook (.ipynb) to Markdown content and metadata. Zero dependencies — uses stdlib jsononly. Supports nbformat 4 and 5.

def parse_notebook(
    content: str,
    source_path: Path | str | None = None,
) -> tuple[str, dict[str, Any]]

Parameters:

  • content: Raw JSON content of the .ipynbfile (caller handles I/O)
  • source_path: Optional path for title fallback when notebook has no title

Returns: Tuple of(markdown_content, metadata_dict)

  • markdown_content: Markdown string — markdown cells as-is, code cells as fenced blocks, outputs as HTML
  • metadata: Dict with title, type: "notebook", notebook.kernel_name, notebook.cell_count, etc.

Raises:

  • json.JSONDecodeError: If content is not valid JSON
  • ValueError: If nbformat is 3 or older

Example:

from patitas import parse_notebook

with open("demo.ipynb") as f:
    content, metadata = parse_notebook(f.read(), "demo.ipynb")

# content: Markdown string ready for parse() or render
# metadata: title, type, notebook{kernel_name, cell_count}, etc.
print(metadata["notebook"]["kernel_name"])  # e.g. "python3"

Used by Bengal for native notebook rendering — drop .ipynbinto content and build.

Markdown

High-level processor combining parsing and rendering.

class Markdown:
    def __init__(
        self,
        *,
        highlight: bool = False,
        plugins: list[str] | None = None,
        directive_registry: DirectiveRegistry | None = None,
    ) -> None: ...

    def __call__(self, source: str) -> str: ...
    def parse(self, source: str, *, source_file: str | None = None, cache: ParseCache | None = None) -> Document: ...
    def parse_many(self, sources: Iterable[str], *, source_file: str | None = None, cache: ParseCache | None = None) -> list[Document]: ...
    def render(self, doc: Document, *, source: str = "") -> str: ...

Example:

from patitas import Markdown

md = Markdown()
html = md("# Hello **World**")
print(html)  # <h1>Hello <strong>World</strong></h1>

# With plugins
md = Markdown(plugins=["table", "math", "strikethrough"])
html = md("| a | b |\n|---|---|\n| 1 | 2 |")

Parse Cache

Content-addressed cache for parsed ASTs. Key is(content_hash, config_hash); value is Document. Enables faster incremental builds (undo/revert, duplicate content) and can replace path-based snapshot caches in consumers like Bengal.

ParseCache protocol

class ParseCache(Protocol):
    def get(self, content_hash: str, config_hash: str) -> Document | None: ...
    def put(self, content_hash: str, config_hash: str, doc: Document) -> None: ...

DictParseCache

In-memory implementation. Not thread-safe — for parallel parsing, use a cache with internal locking.

from patitas import parse, DictParseCache

cache = DictParseCache()
doc = parse("# Hello", cache=cache)
# Second call with same source hits cache
doc2 = parse("# Hello", cache=cache)

hash_content() / hash_config()

Compute cache keys.hash_content(source) returns SHA256 of source. hash_config(config) returns config hash, or"" when text_transformeris set (cache bypassed).

See Performance for optimization details and Serialization for persistence patterns.

Serialization API

Convert AST nodes to/from JSON-compatible dicts and strings. Deterministic output for cache-key stability. Useful for caching parsed ASTs (Bengal incremental builds) and sending ASTs over the wire (Purr SSE).

to_dict() / from_dict()

In-memory dict format — use for caching or when you need to inspect or modify the structure before serializing to JSON.

from patitas import parse, to_dict, from_dict

doc = parse("# Hello **World**")
data = to_dict(doc)
restored = from_dict(data)
assert doc == restored

to_dict(node: Node) -> dict[str, Any]

  • node: Any AST node (Document, Heading, Paragraph, etc.)
  • Returns: JSON-compatible dict with_typediscriminator

from_dict(data: dict[str, Any]) -> Node

  • data: Dict produced by to_dict
  • Returns: Reconstructed typed AST node

to_json() / from_json()

JSON string format — use for persistence, wire transfer, or human inspection.

from patitas import parse, to_json, from_json

doc = parse("# Hello **World**")
json_str = to_json(doc)
restored = from_json(json_str)
assert doc == restored

*to_json(doc: Document, , indent: int | None = None) -> str

  • doc: Document AST root
  • indent: Optional indent for pretty-printing (None = compact)

from_json(data: str) -> Document

  • data: JSON string from to_json
  • Returns: Reconstructed Document

See Serialization for caching and wire-transfer patterns.

Configuration API

Thread-local configuration for advanced use cases.

ParseConfig

Immutable configuration dataclass.

from patitas import ParseConfig

config = ParseConfig(
    tables_enabled=True,
    math_enabled=True,
    strikethrough_enabled=False,
    task_lists_enabled=False,
    footnotes_enabled=False,
    autolinks_enabled=False,
    directive_registry=None,
    strict_contracts=False,
    text_transformer=None,
)

ParseConfig.from_dict()

Create aParseConfigfrom a dictionary. Unknown keys are silently ignored, making this safe for framework integration where config may come from YAML files or external sources.

from patitas import ParseConfig

config = ParseConfig.from_dict({
    "tables_enabled": True,
    "math_enabled": True,
    "unknown_key": "silently ignored",
})
# config.tables_enabled == True
# config.math_enabled == True

parse_config_context()

Context manager for temporary config changes.

from patitas import parse_config_context, ParseConfig, Parser

with parse_config_context(ParseConfig(tables_enabled=True)):
    parser = Parser("| a | b |")
    result = parser.parse()
# Config automatically reset after context

get/set/reset functions

from patitas import get_parse_config, set_parse_config, reset_parse_config

# Get current config
config = get_parse_config()

# Set custom config
set_parse_config(ParseConfig(math_enabled=True))

# Reset to defaults
reset_parse_config()

Low-Level API

Parser

The Markdown parser. Configuration is read from ContextVar.

from patitas import Parser, parse_config_context, ParseConfig

# Simple usage (uses default config)
parser = Parser(source, source_file="example.md")
doc = parser.parse()

# With custom config
with parse_config_context(ParseConfig(tables_enabled=True)):
    parser = Parser(source)
    doc = parser.parse()

Lexer

The state-machine lexer.

from patitas.lexer import Lexer

lexer = Lexer(source)
tokens = list(lexer)

HtmlRenderer

The HTML renderer.

from patitas.renderers.html import HtmlRenderer

renderer = HtmlRenderer(source=source)
html = renderer.render(doc)

Extension Points

set_highlighter()

Set the global syntax highlighter.

from patitas.highlighting import set_highlighter, Highlighter

class MyHighlighter:
    def highlight(self, code: str, lang: str) -> str:
        return f"<pre><code class='{lang}'>{code}</code></pre>"

set_highlighter(MyHighlighter())

set_icon_resolver()

Set the global icon resolver.

from patitas.icons import set_icon_resolver, IconResolver

class MyIcons:
    def resolve(self, name: str) -> str | None:
        return f"<span class='icon-{name}'></span>"

set_icon_resolver(MyIcons())