Migrating from markdown-it-py

Move markdown-it-py render calls, presets, token workflows, and plugins to Wenmode presets, nodes, rules, and renderer handlers.


markdown-it-py is configurable through presets, options, plugins, and rule chains. Wenmode has a similar goal of explicit composition, but uses Python node objects rather than markdown-it token streams.

Simple rendering

markdown-it-py rendering usually starts with a MarkdownIt instance:

markdown-it-py
from markdown_it import MarkdownIt

md = MarkdownIt('commonmark')
html = md.render(text)

The closest Wenmode replacement is:

wenmode
from wenmode import Wenmode

html = Wenmode().render(text)

For GFM-like behavior, use Wenmode’s github preset:

markdown-it-py
from markdown_it import MarkdownIt

md = MarkdownIt('gfm-like')
html = md.render(text)
wenmode
from wenmode import Wenmode
from wenmode.presets import github

html = Wenmode(github).render(text)

Preset and option mapping

markdown-it-py behavior

Wenmode replacement

MarkdownIt('commonmark')

Wenmode() or Wenmode(commonmark)

MarkdownIt('gfm-like')

Wenmode(github) for GFM syntax

.enable('table')

Table rule or github preset

.enable('strikethrough')

Strikethrough rule or github preset

html=True

raw HTML rules plus HTMLRenderer(escape=False) for trusted input

linkify

ExtendedAutolink rule or github preset

disabled rules

custom Wenmode rule list that omits those rules

Token workflows

If your application consumed markdown-it tokens:

markdown-it-py
from markdown_it import MarkdownIt

tokens = MarkdownIt('commonmark').parse(text)

Migrate to Wenmode nodes:

wenmode
from wenmode import Wenmode

root = Wenmode().parse(text)
payload = root.to_ast()

The data model changes from a flat token stream with nesting markers to a tree of node objects. For document analysis, this usually simplifies traversal: walk root.children and descend through nodes that have children.

Plugin migration

markdown-it-py plugins commonly add syntax rules and rendering rules together. In Wenmode, split that work:

  • parser syntax becomes InlineRule, BlockRule, or ContinueRule,

  • document-wide state becomes a root transform with StateKey,

  • HTML output becomes an HTMLRenderer.register() handler,

  • Markdown or RST output becomes handlers on MarkdownRenderer or RSTRenderer,

  • directive-like syntax can use directive rules plus directive renderers.

The old integration often attaches a plugin to a MarkdownIt instance:

markdown-it-py
from markdown_it import MarkdownIt
from my_package import my_plugin

md = MarkdownIt('commonmark').use(my_plugin)
html = md.render(text)

In Wenmode, make parser rules and renderer handlers explicit:

wenmode
from wenmode import Wenmode
from my_package.wenmode_rules import MyInlineRule

wenmode = Wenmode([MyInlineRule])
html = wenmode.render(text)

See Custom rules for custom rules and renderer registration.

Renderer migration

markdown-it-py render rules attach output callbacks to token types:

markdown-it-py
from markdown_it import MarkdownIt


def render_text(renderer, tokens, index, options, env):
    return tokens[index].content


md = MarkdownIt('commonmark')
md.add_render_rule('text', render_text)
html = md.render(text)

Wenmode renderer handlers attach output callbacks to node types:

wenmode
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)

Raw HTML and security

markdown-it-py applications often use the html option to allow raw HTML. In markdown-it-py this is parser configuration:

markdown-it-py
from markdown_it import MarkdownIt

md = MarkdownIt('commonmark', {'html': True})
html = md.render(text)

In Wenmode, raw HTML can be parsed while still being escaped by the default HTML renderer. To pass raw HTML through, configure the renderer explicitly:

wenmode
from wenmode import HTMLRenderer, Wenmode

html = Wenmode(renderer=HTMLRenderer(escape=False)).render(text)

Keep the default renderer for untrusted user-authored Markdown.

Streaming

If your markdown-it-py integration rendered whole documents but your application would benefit from incremental responses, Wenmode can use a streaming preset:

markdown-it-py
from markdown_it import MarkdownIt

html = MarkdownIt('commonmark').render(text)
send(html)
wenmode
from wenmode import Wenmode
from wenmode.presets import streaming

for chunk in Wenmode(streaming).stream(text):
    send(chunk)

The streaming preset disables reference-style links, reference-style images, footnotes, and other features that require document-wide deferred inline resolution.

Checklist

  • Choose commonmark, github, or streaming.

  • Convert token-stream code to node traversal or to_ast().

  • Split plugins into parser rules, transforms, and renderer handlers.

  • Review raw HTML and linkification behavior.

  • Compare rendered HTML for tables, strikethrough, task lists, and autolinks.