Migrating from Mistune¶
Replace Mistune helpers, plugins, AST usage, and renderer subclasses with Wenmode presets, explicit rules, node transforms, and renderer handlers.
Mistune and Wenmode share design DNA, but their extension models are different. Mistune centers on Markdown instances, plugins, and renderers. Wenmode centers on explicit parser rules, mdast-compatible nodes, document transforms, and renderer dispatch.
Simple HTML rendering¶
Mistune’s convenience helper converts Markdown directly to HTML:
import mistune
html = mistune.html(text)
The closest Wenmode replacement is:
from wenmode import Wenmode
html = Wenmode().render(text)
Reusable parser instances¶
Mistune applications often create a reusable Markdown instance:
import mistune
markdown = mistune.create_markdown(renderer='html', plugins=['table'])
html = markdown(text)
In Wenmode, keep a reusable Wenmode object:
from wenmode import Wenmode
from wenmode.presets import github
wenmode = Wenmode(github)
html = wenmode.render(text)
Parser state is created per parse, so definitions, footnotes, abbreviations, and deferred inline queues do not leak between calls.
Plugin and GFM setup¶
Choose github when your Mistune use relied on GFM-like features such as
tables, task list items, strikethrough, extended autolinks, or footnotes:
import mistune
markdown = mistune.create_markdown(
plugins=['table', 'strikethrough', 'footnotes', 'url'],
)
html = markdown(text)
from wenmode import Wenmode
from wenmode.presets import github
wenmode = Wenmode(github)
html = wenmode.render(text)
For a smaller dialect, start from commonmark and add only the Wenmode rules
that correspond to the Mistune plugins you actually used.
HTML safety behavior¶
Mistune configurations are often used as direct HTML filters. When migrating, check whether raw HTML was supposed to pass through.
If the old integration intentionally allowed raw HTML, it often looked like this:
import mistune
markdown = mistune.create_markdown(escape=False)
html = markdown(text)
Use Wenmode raw HTML passthrough only for trusted or separately sanitized input:
from wenmode import HTMLRenderer, Wenmode
wenmode = Wenmode(renderer=HTMLRenderer(escape=False))
html = wenmode.render(text)
Wenmode’s default HTMLRenderer() escapes raw HTML and sanitizes unsafe URLs, so
keep the default renderer for user-authored content.
To keep raw HTML syntax as text in the AST, remove HtmlBlock and RawHtml
from the rule list instead of relying only on renderer escaping.
Plugin mapping¶
Mistune plugins do not map one-to-one to Wenmode APIs. Use this table as a starting point:
Mistune behavior |
Wenmode replacement |
|---|---|
|
|
|
|
|
|
|
|
custom inline plugin |
custom |
custom block plugin |
custom |
plugin state |
|
renderer plugin |
renderer handler registered with |
AST migration¶
If you used Mistune’s AST renderer:
import mistune
markdown = mistune.create_markdown(renderer='ast')
tokens = markdown(text)
Migrate code to Wenmode nodes:
from wenmode import Wenmode
root = Wenmode().parse(text)
payload = root.to_ast()
Wenmode’s to_ast() output uses mdast-style dictionaries where possible:
root, paragraph, heading, text, link, image, code, html, and
extension node types such as table, footnoteReference, and directives.
For code that previously walked Mistune tokens, prefer direct node traversal
when you need Python objects, or root.to_ast() when you need serializable data.
Renderer migration¶
Mistune custom renderers:
import mistune
class MyRenderer(mistune.HTMLRenderer):
def text(self, text: str) -> str:
return mistune.escape(text)
markdown = mistune.create_markdown(renderer=MyRenderer())
html = markdown(text)
Become Wenmode renderer handlers:
from wenmode import HTMLRenderer
from wenmode.nodes import Text
from wenmode.renderers import RenderContext
@HTMLRenderer.register('text')
def render_text(renderer: HTMLRenderer, node: Text, context: RenderContext) -> str:
return renderer.escape_html(node.value)
For custom node types, define the node in your extension and register handlers for every output format you support. See Custom rules for a complete custom node example.
Checklist¶
Pick
commonmarkorgithubbefore porting individual plugins.Decide whether raw HTML should be escaped or passed through.
Replace Mistune plugins with rules, transforms, directive renderers, or renderer handlers.
Compare generated HTML for real documents, especially tables, footnotes, raw HTML, and autolinks.
Update tests that asserted Mistune token shapes to assert Wenmode nodes or
to_ast()dictionaries instead.