mrkeyoor.com_
Sun 20 Sept 11:44 UTC
PyPIUtilsupdated 20 Sept 2026

mistune review

Our Python 3.12 sandbox installed Mistune 3.3.4 in 0.2 seconds and imported it in 0.16 seconds. It turns Markdown into HTML, a dictionary AST, normalized Markdown, or reStructuredText, with hooks for custom renderers and syntax plugins. Tables, footnotes, task lists, math, definition lists, directives, and formatting extensions are available without changing parsers. Release 3.3.4 corrects malformed table handling and a definition-list tab case, caps deeply nested image-alt parsing, and adjusts the inline parser using work from the author's newer Wenmode parser.

Verdict

Mistune 3.3.4 is a good fit when Python code needs a configurable parser, AST, or custom renderer without a large extension stack. Configure raw HTML explicitly, sanitize user output, and compare Wenmode before committing to new parser-heavy work.

We installed it

Lab card: what happened when we installed mistuneScreenshot of mistune documentation
Install✓ · 0.2s1 package on disk · 1 MB
Importimport mistune in 0.16s · pure Python · py.typed · requires Python >=3.8
Known vulns0(pip-audit)

Answers from our run

Does mistune install cleanly?

Yes. In a fresh container with an empty cache, pip install mistune finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.

What does mistune need to run?

Python >=3.8, and nothing compiled: it is pure Python. In our run import mistune succeeded in 0.16s, and the package ships py.typed for type checkers.

mistune or markdown-it-py: which should you use?

markdown-it-py: Use it for a CommonMark-oriented token stream and compatibility with markdown-it concepts. Mistune 3.3.4 is a good fit when Python code needs a configurable parser, AST, or custom renderer without a large extension stack.

When should you not use mistune?

You plan to send mistune.html() output from users straight to a browser: that shortcut permits raw HTML and no renderer is an HTML sanitizer

API stability3/5Within v3, create_markdown, renderer classes, plugin registration, and dictionary nodes have been consistent enough for patch updates. Release 3.3.4 changes parsing results at documented edge cases without announcing a public constructor break. Across the package's life, 0.x, 2.x, and 3.x are materially different. Renderer subclasses and AST walkers carry the most migration risk because application code depends on method arguments and node fields.
Docs4/5The documentation has separate paths for basic rendering, plugins, directives, renderer subclasses, AST use, and upgrades, with executable examples rather than an option inventory alone. PyPI links to the same current site. The biggest missing warning is placement: the security difference between mistune.html and create_markdown escape defaults takes reading across pages, although it should be visible beside the first one-line example.
Maintenance4/5PyPI published 3.3.4 on 2026-07-22, and GitHub showed a push on 2026-08-21. The release fixed specific table, definition-list, alt-text, and inline-parser cases. GitHub reported 21 open issues and pull requests combined. The repository is active, while the README's promotion of Wenmode shows that new parser architecture work is moving elsewhere. Mistune still receives concrete correctness fixes today.
Ecosystem4/5Mistune draws roughly 17.5 million weekly downloads, and GitHub showed 3,063 stars. It appears in Python documentation and notebook stacks, while bundled plugins cover the syntax most publishing products ask for first. It can emit multiple targets and accepts custom renderers. Python-Markdown still has the wider third-party extension catalog, so uncommon authoring syntax may require local plugin code here.

Use it if

  • A Python service needs one reusable Markdown callable that can emit HTML or structured nodes
  • You need to override one output node, such as fenced code or links, through a renderer subclass
  • Your accepted syntax includes Mistune's table, footnote, task-list, math, definition-list, or directive plugins
  • A pure Python wheel with py.typed suits your deployment and static type checks
Skip it if

Setup reality

Our clean mistune==3.3.4 install took 0.2 seconds and left one installed package occupying 1 MB. pip-audit found zero known vulnerabilities. The distribution has one direct dependency, conditional typing-extensions for Python below 3.11, and requires Python 3.8 or newer. It is pure Python, carries a BSD-3-Clause license, includes py.typed, and imported successfully in 0.16 seconds on Python 3.12.

Choose the constructor deliberately. mistune.html(source) is the short path and allows raw HTML. mistune.create_markdown() builds an HTML renderer that escapes raw tags by default and enables no plugins. Escaping tags is not a full allowlist policy for links, attributes, or HTML emitted by custom code. For user-authored content, sanitize the rendered string with a package such as nh3 before placing it in a page.

Build the configured Markdown callable once and reuse it. Plugin names may be strings or callable registrations. FencedDirective and RSTDirective wrap different directive syntaxes, so registering an inner directive class alone is incomplete. Custom HTMLRenderer methods must use v3 signatures and escape any source text they interpolate. AST leaves commonly store raw, containers store children, and plugins can attach attrs; walkers should branch on node type instead of assuming one dictionary shape.

Release 3.3.4 changes output for several edge cases. A table-like block with an invalid delimiter row is rejected instead of being consumed as a table. A tab after a definition marker no longer turns the definition into code. Deep image-alt nesting is bounded, and inline parsing received correctness and speed changes. Snapshot rendered output around these cases before upgrading a publishing pipeline. The CLI helps inspect results, but it uses the same plugin and escaping choices as the Python API.

Patterns

Render trusted Markdown with the shortcut render-trusted-markdown

import mistune

html = mistune.html('# Status\n\n**ready**')

The shortcut accepts raw HTML. Reserve it for source whose embedded HTML is already trusted.

Create a renderer that escapes raw tags escape-source-html

import mistune

render = mistune.create_markdown(escape=True)
html = render('<script>alert(1)</script>')

Escaping prevents raw tags from passing through. Apply an HTML sanitizer as a separate step for user content.

Opt into the syntax your product accepts enable-syntax-plugins

import mistune

render = mistune.create_markdown(
    escape=True,
    plugins=['table', 'footnotes', 'task_lists'],
)
html = render('- [x] published')

create_markdown enables no plugins unless you supply them. A short explicit list keeps stored syntax predictable.

Reuse one parser across calls reuse-configured-parser

import mistune

render_article = mistune.create_markdown(
    escape=True, plugins=['table', 'strikethrough']
)

def to_html(source: str) -> str:
    return render_article(source)

Parser creation assembles rules and hooks. Construct it at module scope instead of rebuilding it per request.

Return AST dictionaries instead of HTML produce-syntax-tree

import mistune

parse = mistune.create_markdown(renderer=None)
nodes = parse('hello **world**')

Expect raw on many leaves, children on containers, and attrs on some plugin nodes. Node type should drive traversal.

Collect plain text from an AST walk-text-nodes

def collect_text(node):
    if 'raw' in node:
        return node['raw']
    return ''.join(collect_text(child) for child in node.get('children', []))

plain = ''.join(collect_text(node) for node in nodes)

This deliberately discards structure and plugin metadata. Use type-specific branches for a semantic transformation.

Override fenced code rendering customize-code-blocks

import mistune

class CodeRenderer(mistune.HTMLRenderer):
    def block_code(self, code, info=None):
        escaped = mistune.escape(code)
        return f'<pre><code>{escaped}</code></pre>\n'

render = mistune.create_markdown(renderer=CodeRenderer())

Escape source when composing HTML yourself. Renderer method signatures from older Mistune majors are not interchangeable with v3.

Write normalized Markdown output normalize-markdown

import mistune
from mistune.renderers.markdown import MarkdownRenderer

normalize = mistune.create_markdown(renderer=MarkdownRenderer())
clean = normalize('# Title\n\nText')

A target renderer may lack methods for an enabled plugin. Test the complete syntax list before using this for round trips.

Render reStructuredText convert-to-rst

import mistune
from mistune.renderers.rst import RSTRenderer

to_rst = mistune.create_markdown(renderer=RSTRenderer())
rst = to_rst('# Title\n\nSome **bold** text.')

Markdown extensions without an equivalent reStructuredText node need a custom method or a documented fallback.

Enable fenced admonitions register-fenced-directive

import mistune
from mistune.directives import Admonition, FencedDirective

render = mistune.create_markdown(plugins=[
    FencedDirective([Admonition()]),
])
html = render('~~~{warning}\nCheck the input\n~~~')

RSTDirective handles the double-dot form. The wrapper selects parsing rules for the directive syntax.

Mark math for a later typesetter preserve-math

import mistune

render = mistune.create_markdown(plugins=['math'])
html = render('Inline $a^2$ and block: \n\n$$b^2$$')

The plugin emits math markers; KaTeX, MathJax, or another renderer must still typeset the expression.

Compare HTML and AST output from the shell inspect-from-cli

python -m mistune -f README.md -o readme.html
python -m mistune -f README.md -r ast

Use CLI output for diagnosis. Reproduce the application's renderer, escape, and plugin settings before comparing results.

Alternatives

PackageRegistryPick it when
markdown-it-pyPyPIUse it for a CommonMark-oriented token stream and compatibility with markdown-it concepts
MarkdownPyPIUse Python-Markdown when its extension catalog is the deciding requirement
wenmodePyPIUse the same author's newer parser for mdast output, streaming, and safer HTML defaults
mistletoePyPIUse it when a CommonMark AST and renderer-first design better fit your transformations

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.