Skip to main content

Modern Markdown parser for Python 3.14t — CommonMark compliant, free-threading ready, 40-50% faster than mistune

Project description

ฅᨐฅ Patitas

PyPI version Build Status Python 3.14+ License: MIT CommonMark ReDoS Safe

The secure, typed Markdown parser for modern Python.

from patitas import Markdown

md = Markdown()
html = md("# Hello **World**")

Why Patitas?

Patitas mistune markdown-it-py
ReDoS-proof ✅ O(n) FSM lexer ❌ Regex-based ✅ Token-based
CommonMark 0.31.2 ✅ Partial 0.31.2 ✅
Free-threading ✅ Python 3.14t safe ✅ Works Crashes
Typed AST ✅ Frozen dataclasses Dict[str, Any] ❌ Token objects
Dependencies Zero Zero Zero
Directives ✅ MyST syntax RST-style Plugin required

Patitas is the only CommonMark-compliant parser with typed AST that works safely under Python 3.14t free-threading.


Installation

pip install patitas

Requires Python 3.14+

Optional extras:

pip install patitas[syntax]      # Syntax highlighting via Rosettes
pip install patitas[all]         # All optional features

Quick Start

Function Description
parse(source) Parse Markdown to typed AST
parse_incremental(new, prev, ...) Re-parse only the changed region (O(change))
render(doc) Render AST to HTML
Markdown() All-in-one parser and renderer

Security

Patitas is immune to ReDoS attacks.

Traditional Markdown parsers use regex patterns vulnerable to catastrophic backtracking:

# Malicious input that can freeze regex-based parsers
evil = "a](" + "\\)" * 10000

# mistune: hangs for seconds/minutes
# Patitas: completes in milliseconds (O(n) guaranteed)

Patitas uses a hand-written finite state machine lexer:

  • Single character lookahead — No backtracking, ever
  • Linear time guaranteed — Processing time scales with input length
  • Safe for untrusted input — Use in web apps, APIs, user-facing tools

Learn more about Patitas security →


Performance

Python 3.14t (free-threading) — 652 CommonMark examples:

Parser Single Thread 4 Threads Thread-safe?
mistune 11ms 4ms
Patitas 17ms 7ms
markdown-it-py 20ms CRASH
# Run benchmarks yourself
PYTHONPATH=src python3.14t benchmarks/benchmark_vs_mistune.py

Key insights:

  • mistune is faster — regex engines are highly optimized
  • Patitas scales linearly — 2.5x speedup with 4 threads
  • markdown-it-py crashes under free-threading (race condition in URL encoding)

Patitas prioritizes safety over raw speed: O(n) guaranteed parsing, typed AST, and full thread-safety.


Features

Feature Description
CommonMark Full 0.31.2 spec compliance (652 examples)
Typed AST Immutable frozen dataclasses with slots
Plugins Tables, footnotes, math, strikethrough, task lists
Directives MyST-style blocks (admonition, dropdown, tabs)
Roles Inline semantic markup
Incremental Re-parse only changed blocks — O(change) not O(document)
Thread-safe Zero shared mutable state, free-threading ready

Usage

Basic Parsing
from patitas import parse, render

# Parse to AST
doc = parse("# Hello **World**")

# Render to HTML
html = render(doc)
# <h1 id="hello-world">Hello <strong>World</strong></h1>
Typed AST — IDE autocomplete, catch errors at dev time
from patitas import parse
from patitas.nodes import Heading, Paragraph, Strong

doc = parse("# Hello **World**")
heading = doc.children[0]

# Full type safety
assert isinstance(heading, Heading)
assert heading.level == 1

# IDE knows the types!
for child in heading.children:
    if isinstance(child, Strong):
        print(f"Bold text: {child.children}")

All nodes are @dataclass(frozen=True, slots=True) — immutable and memory-efficient.

Directives — MyST-style blocks
:::{note}
This is a note admonition.
:::

:::{warning}
This is a warning.
:::

:::{dropdown} Click to expand
Hidden content here.
:::

:::{tab-set}

:::{tab-item} Python
Python code here.
:::

:::{tab-item} JavaScript
JavaScript code here.
:::

:::
Custom Directives — Extend with your own
from patitas import Markdown, create_registry_with_defaults

# Define a custom directive
class AlertDirective:
    names = ("alert",)
    token_type = "alert"
    
    def render(self, directive, renderer):
        return f'<div class="alert">{directive.title}</div>'

# Extend defaults with your directive
builder = create_registry_with_defaults()  # Has admonition, dropdown, tabs
builder.register(AlertDirective())

# Use it
md = Markdown(directive_registry=builder.build())
html = md(":::{alert} This is important!\n:::")
Syntax Highlighting

With pip install patitas[syntax]:

from patitas import Markdown

md = Markdown(highlight=True)

html = md("""
```python
def hello():
    print("Highlighted!")

""")


Uses [Rosettes](https://github.com/lbliii/rosettes) for O(n) highlighting.

</details>

<details>
<summary><strong>Free-Threading</strong> — Python 3.14t</summary>

```python
from concurrent.futures import ThreadPoolExecutor
from patitas import parse

documents = ["# Doc " + str(i) for i in range(1000)]

with ThreadPoolExecutor() as executor:
    # Safe to parse in parallel — no shared mutable state
    results = list(executor.map(parse, documents))

Patitas is designed for Python 3.14t's free-threading mode (PEP 703).


Migrate from mistune

# Before (mistune)
import mistune
md = mistune.create_markdown()
html = md(source)

# After (patitas) — same API!
from patitas import Markdown
md = Markdown()
html = md(source)

Key differences:

  • Patitas uses MyST directive syntax (:::{note}) vs mistune's RST (.. note::)
  • Patitas AST is typed dataclasses vs mistune's Dict[str, Any]
  • Patitas is ReDoS-proof; mistune uses regex

Full migration guide →


The Bengal Ecosystem

A structured reactive stack — every layer written in pure Python for 3.14t free-threading.

ᓚᘏᗢ Bengal Static site generator Docs
∿∿ Purr Content runtime
⌁⌁ Chirp Web framework Docs
=^..^= Pounce ASGI server Docs
)彡 Kida Template engine Docs
ฅᨐฅ Patitas Markdown parser ← You are here Docs
⌾⌾⌾ Rosettes Syntax highlighter Docs

Python-native. Free-threading ready. No npm required.


Development

git clone https://github.com/lbliii/patitas.git
cd patitas
uv sync --group dev
pytest

Run benchmarks:

pip install mistune markdown-it-py
python benchmarks/benchmark_vs_mistune.py

License

MIT License — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

patitas-0.2.0.tar.gz (201.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

patitas-0.2.0-py3-none-any.whl (199.7 kB view details)

Uploaded Python 3

File details

Details for the file patitas-0.2.0.tar.gz.

File metadata

  • Download URL: patitas-0.2.0.tar.gz
  • Upload date:
  • Size: 201.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for patitas-0.2.0.tar.gz
Algorithm Hash digest
SHA256 e1fb064b612736ada7a64b3f517dc1dd8e17eca8c4af1991103f57023ddff028
MD5 09281c344c1884f57d34d53e9f24d437
BLAKE2b-256 838307bbbf2c10b471787f4745f44df085d2d43b7d51bae96dabcfc8994fdc16

See more details on using hashes here.

Provenance

The following attestation bundles were made for patitas-0.2.0.tar.gz:

Publisher: python-publish.yml on lbliii/patitas

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file patitas-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: patitas-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 199.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for patitas-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 31c50ae5295f8e75d5242fc4828f6d9e55e4e356ad0eeeb74af6a60f3a8c7078
MD5 a52831b9f6a104d5a8d010993242b372
BLAKE2b-256 99c18e534218e5059ed73ff4960504f785c2acc21664ee0642d9fb59344843dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for patitas-0.2.0-py3-none-any.whl:

Publisher: python-publish.yml on lbliii/patitas

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page