From 1209f3421e5057bb2525c7059c1a38ddf205ef2e Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:15:20 -0700 Subject: [PATCH] fix: apply escape flag to a user-supplied HTML renderer create_markdown() only passed the escape flag to the renderer it built itself, so passing escape=False together with a custom HTMLRenderer subclass silently left HTML escaped. escape now defaults to None, meaning 'keep the renderer's own setting', and an explicit True/False is applied to a supplied HTMLRenderer instance as well. Closes #420 --- src/mistune/__init__.py | 10 +++++++--- tests/test_misc.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/mistune/__init__.py b/src/mistune/__init__.py index 42b5d6f..60ab0f3 100644 --- a/src/mistune/__init__.py +++ b/src/mistune/__init__.py @@ -22,14 +22,15 @@ def create_markdown( - escape: bool = True, + escape: Optional[bool] = None, hard_wrap: bool = False, renderer: Optional[RendererRef] = "html", plugins: Optional[Iterable[PluginRef]] = None, ) -> Markdown: """Create a Markdown instance based on the given condition. - :param escape: Boolean. If using html renderer, escape html. + :param escape: Boolean. If using html renderer, escape html. When it is + ``None``, the renderer keeps its own escape setting. :param hard_wrap: Boolean. Break every new line into ``
``. :param renderer: renderer instance, default is HTMLRenderer. :param plugins: List of plugins. @@ -47,7 +48,10 @@ def create_markdown( # explicit and more similar to 2.x's API renderer = None elif renderer == "html": - renderer = HTMLRenderer(escape=escape) + renderer = HTMLRenderer(escape=True if escape is None else escape) + elif escape is not None and isinstance(renderer, HTMLRenderer): + # a renderer instance was given, honor the explicit escape flag + renderer._escape = escape inline = InlineParser(hard_wrap=hard_wrap) real_plugins: Optional[Iterable[Plugin]] = None diff --git a/tests/test_misc.py b/tests/test_misc.py index e3a834f..bbdce68 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -17,6 +17,20 @@ def _add_name(md, state): md.parse("", state) self.assertEqual(state.env["name"], "test") + def test_escape_applies_to_custom_renderer(self): + class CustomRenderer(mistune.HTMLRenderer): + pass + + md = mistune.create_markdown(renderer=CustomRenderer(), escape=False) + self.assertEqual(md("hi").strip(), "

hi

") + + md = mistune.create_markdown(renderer=CustomRenderer(escape=False), escape=True) + self.assertEqual(md("hi").strip(), "

<b>hi</b>

") + + # without an explicit escape flag the renderer keeps its own setting + md = mistune.create_markdown(renderer=CustomRenderer(escape=False)) + self.assertEqual(md("hi").strip(), "

hi

") + def test_hard_wrap(self): md = mistune.create_markdown(escape=False, hard_wrap=True) result = md("foo\nbar")