Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-mistune for openSUSE:Factory checked in at 2026-05-12 19:26:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-mistune (Old) and /work/SRC/openSUSE:Factory/.python-mistune.new.1966 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-mistune" Tue May 12 19:26:30 2026 rev:27 rq:1352489 version:3.2.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-mistune/python-mistune.changes 2026-03-17 19:04:24.308441940 +0100 +++ /work/SRC/openSUSE:Factory/.python-mistune.new.1966/python-mistune.changes 2026-05-12 19:26:53.491642265 +0200 @@ -1,0 +2,17 @@ +Mon May 11 11:06:28 UTC 2026 - Nico Krapp <[email protected]> + +- Update to 3.2.1 (fixes CVE-2026-33079 - bsc#1264347, + CVE-2026-44897 - bsc#1264750, CVE-2026-44708 - bsc#1264751, + CVE-2026-33441 - bsc#1264752, CVE-2026-44896 - bsc#1264754) + * Resolve Windows compatibility issues in file inclusion and tests + - by @Yuki9814 + * Escape html text - by @lepture + * Update link reference - by @lepture + * Handle escaped dollar signs in inline math - by @saschabuehrle + * Escape id of toc - by @lepture + * Escape id of headings - by @lepture + * Remove double-encoding of image alt text - by @lawrence3699 + * Escape xml for math plugin - by @lepture + * Use strict regex for image's height and width - by @lepture + +------------------------------------------------------------------- Old: ---- mistune-3.2.0.tar.gz New: ---- mistune-3.2.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-mistune.spec ++++++ --- /var/tmp/diff_new_pack.oVx6TR/_old 2026-05-12 19:26:53.991662988 +0200 +++ /var/tmp/diff_new_pack.oVx6TR/_new 2026-05-12 19:26:53.995663154 +0200 @@ -19,7 +19,7 @@ %define modname mistune %{?sle15_python_module_pythons} Name: python-%{modname} -Version: 3.2.0 +Version: 3.2.1 Release: 0 Summary: Python Markdown parser with renderers and plugins License: BSD-3-Clause ++++++ mistune-3.2.0.tar.gz -> mistune-3.2.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/.github/SECURITY.md new/mistune-3.2.1/.github/SECURITY.md --- old/mistune-3.2.0/.github/SECURITY.md 1970-01-01 01:00:00.000000000 +0100 +++ new/mistune-3.2.1/.github/SECURITY.md 2026-05-03 16:30:25.000000000 +0200 @@ -0,0 +1,4 @@ +# Security + +If you discover a security vulnerability, **do not submit a public issue or patch**. +Instead, please report it privately through the **GitHub Security** tab. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/docs/advanced.rst new/mistune-3.2.1/docs/advanced.rst --- old/mistune-3.2.0/docs/advanced.rst 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/docs/advanced.rst 2026-05-03 16:30:25.000000000 +0200 @@ -150,3 +150,265 @@ the directives part of the documentation. These are defined in the ``mistune/directives``, you can learn how to write a new directive by reading the source code in ``mistune/directives/``. + + +.. _parsing-ast-tokens: + +Parsing AST tokens +------------------ + +Mistune provides direct access to AST tokens by creating a markdown object +via ``mistune.create_markdown(renderer='ast')`` (see :ref:`abstract-syntax-tree`). +By walking down the AST returned from the markdown object, you can integrate +Mistune's parser into other systems. + +.. code-block:: python + + import mistune + + markdown = mistune.create_markdown(renderer='ast') + + tokens = markdown( + '''# Title + + Subtitle + -------- + + Hello World!''' + ) + + stk = list(reversed(tokens)) + while stk: + token = stk.pop() + print({k:v for k, v in token.items() if k != 'children'}) + if 'children' in token: + for child in reversed(token['children']): + stk.append(child) + +Below is the documentation for the list of tokens that can occur in +``renderer='ast'`` mode. + +Token structure +~~~~~~~~~~~~~~~ + +An AST token is a ``dict`` containing an item whose key is ``'type'`` and value +is a string representing the token type (such as ``'text'``, ``'emphasis'``, +``'strong'``). If the token has children, they are represented as a +``list`` under the ``'children'`` key. + +Inline elements +~~~~~~~~~~~~~~~ + +.. code-block:: python + + { 'type': 'linebreak' } + { 'type': 'softbreak' } + { 'type': 'text', 'raw': str } + { 'type': 'emphasis', 'children': list[dict] } + { 'type': 'strong', 'children': list[dict] } + { 'type': 'codespan', 'raw': str } + { 'type': 'inline_html', 'raw': str } + + # links and images + # + # 'children' contains elements in the link text section. If you + # write something like [**text**](url), **text** goes to 'children'. + # This behavior is identical for both images and links, but the HTML + # renderer extracts only the text part of children when actually + # putting it into 'alt' attribute (e.g.,  returns + # <img src="url" alt="text">, not <img src="url" alt="**text**">) + # + # for reference links and images (like [text][label], [label], etc.), + # 'ref' and 'label' are also given. Both contain the same content, + # but 'ref' is an uppercase version, while 'label' is case-sensitive. + # + { + 'type': 'image', + 'children': list[dict], # link text + 'attrs': { + 'url': str, + 'title': str | None # is None if not given + }, + 'ref': str, # omitted if not reference links and images + 'label': str # omitted if not reference links and images + } + { + 'type': 'link', + 'children': list[dict], # link text + 'attrs': { + 'url': str, + 'title': str | None # is None if not given + }, + 'ref': str, # omitted if not reference links and images + 'label': str # omitted if not reference links and images + } + +Block elements +~~~~~~~~~~~~~~ + +.. code-block:: python + + { 'type': 'blank_line' } + { 'type': 'thematic_break' } + { 'type': 'paragraph', 'children': list[dict] } + + # 'block_text' is a special text block that occurs in 'tight' lists. + # + # when a list is tight (i.e., there is no blank line between any list + # items or their children), and if a leaf list item contains only a + # paragraph, that paragraph's 'type' is changed to 'block_text' + # ('children' remains the same). + # + # block_texts are immediately put between <li>...</li>, where paragraphs + # (occurring in 'loose' lists) are rendered like <li><p>...</p></li>. + # + { 'type': 'block_text', 'children': list[dict] } + + # 'style' can be 'atx' or 'setext' + { + 'type': 'heading', + 'children': list[dict], + 'attrs': {'level': int}, + 'style': str + } + + { 'type': 'block_quote', 'children': list[dict] } + { 'type': 'block_html', 'raw': str } + { 'type': 'block_code', 'raw': str, 'style': 'indent' } + + # fenced block code + { + 'type': 'block_code', + 'raw': str, + 'style': 'fenced', + 'marker': str, + 'attrs': {'info': str} # appears if info string is given + } + +List elements +~~~~~~~~~~~~~ + +.. code-block:: python + + { + 'type': 'list', + 'children': [{'type': 'list_item', 'children': list[dict]}, ...], + 'tight': bool, # whether the list is 'tight' or 'loose' + 'bullet': str, # list marker character + 'attrs': { + 'depth': int, + 'ordered': bool, # whether the list is ordered or unordered + 'start': int # appears if the list is ordered and start != 1 + } + } + +Plugin elements +~~~~~~~~~~~~~~~ + +.. code-block:: python + + # strikethrough, mark, insert, superscript, and subscript plugin + { 'type': 'strikethrough', 'children': list[dict] } + { 'type': 'mark', 'children': list[dict] } + { 'type': 'insert', 'children': list[dict] } + { 'type': 'superscript', 'children': list[dict] } + { 'type': 'subscript', 'children': list[dict] } + + # footnotes plugin + { 'type': 'footnote_ref', 'raw': str, 'attrs': {'index': int} } + { + 'type': 'footnotes', + 'children': [ + { + 'type': 'footnote_item', + 'children': [{'type': 'paragraph', 'children': list[dict]}], + 'attrs': {'key': str, 'index': int} + }, + ... + ] + } + + # table plugin + { + 'type': 'table', + 'children': [ + { + 'type': 'table_head', + 'children': [ + { + 'type': 'table_cell', + 'children': list[dict], + 'attrs': { + # 'align' is 'center', 'left', 'right', or None + 'align': str | None, + 'head': True + } + }, + ... + ] + }, + { + 'type': 'table_body', + 'children': { + 'type': 'table_row', + 'children': [ + { + 'type': 'table_cell', + 'children': list[dict], + 'attrs': { + # 'align' is 'center', 'left', 'right', or None + 'align': str | None, + 'head': False + } + }, + ... + ] + } + } + ] + } + + # url plugin does not add new elements + # (it uses 'link' element just like normal links) + + # task_lists plugin + # + # task_list_item appears in the same contexts as list_item. + # + { + 'type': 'task_list_item', + 'children': list[dict], + 'attrs': {'checked': bool} + } + + # def_list plugin + # + # similar to regular lists, sole paragraphs in def_list_items are + # converted to 'block_texts' if the definition list is tight. + # + { + 'type': 'def_list', + 'children': [ + { 'type': 'def_list_head', 'children': list[dict] }, + { 'type': 'def_list_item', 'children': list[dict] }, + ... + ] + } + + # abbr plugin + { + 'type': 'abbr', + 'children': [{'type': 'text', 'raw': str}], + 'attrs': {'title': str} + } + + # math plugin + { 'type': 'block_math', 'raw': str } + { 'type': 'inline_math', 'raw': str } + + # ruby plugin + { 'type': 'ruby', 'raw': str, 'attrs': {'rt': str} } + + # spoiler plugin + { 'type': 'block_spoiler', 'children': list[dict] } + { 'type': 'inline_spoiler', 'children': list[dict] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/docs/changes.rst new/mistune-3.2.1/docs/changes.rst --- old/mistune-3.2.0/docs/changes.rst 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/docs/changes.rst 2026-05-03 16:30:25.000000000 +0200 @@ -3,6 +3,21 @@ Here is the full history of mistune v3. +Version 3.2.1 +------------- + +**Released on May 3, 2026** + +* Escape link in ``render_toc_ul``. +* Escape text in math plugin. +* Fix regex for math plugin. +* Escape heading's ID attribute. +* Fix ``LINK_TITLE_RE`` to prevent DoS. +* Escape class attribute for admonition directive. +* Remove double-encoding of image alt text. +* Escape class attribute for image directive. +* Fix width/height attribute for image directive. + Version 3.2.0 ------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/docs/guide.rst new/mistune-3.2.1/docs/guide.rst --- old/mistune-3.2.0/docs/guide.rst 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/docs/guide.rst 2026-05-03 16:30:25.000000000 +0200 @@ -83,6 +83,8 @@ at :ref:`renderers`. +.. _abstract-syntax-tree: + Abstract syntax tree -------------------- @@ -108,3 +110,5 @@ It is also possible to pass ``renderer='ast'`` to create the markdown instance:: markdown = mistune.create_markdown(renderer='ast') + +For details on how to parse these tokens, see :ref:`parsing-ast-tokens`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/__init__.py new/mistune-3.2.1/src/mistune/__init__.py --- old/mistune-3.2.0/src/mistune/__init__.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/__init__.py 2026-05-03 16:30:25.000000000 +0200 @@ -97,5 +97,5 @@ "markdown", ] -__version__ = "3.2.0" +__version__ = "3.2.1" __homepage__ = "https://mistune.lepture.com/" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/directives/admonition.py new/mistune-3.2.1/src/mistune/directives/admonition.py --- old/mistune-3.2.0/src/mistune/directives/admonition.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/directives/admonition.py 2026-05-03 16:30:25.000000000 +0200 @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING, Any, Dict, Match +from ..util import escape as escape_text from ._base import BaseDirective, DirectivePlugin @@ -64,7 +65,7 @@ html = '<section class="admonition ' + name _cls = attrs.get("class") if _cls: - html += " " + _cls + html += " " + escape_text(_cls) return html + '">\n' + text + "</section>\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/directives/image.py new/mistune-3.2.1/src/mistune/directives/image.py --- old/mistune-3.2.0/src/mistune/directives/image.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/directives/image.py 2026-05-03 16:30:25.000000000 +0200 @@ -13,7 +13,7 @@ __all__ = ["Image", "Figure"] -_num_re = re.compile(r"^\d+(?:\.\d*)?") +_num_re = re.compile(r"^\d+(?:\.\d*)?(?:px|ch|em|rem|ex|rex|vw|vh|%)?$") _allowed_aligns = ["top", "middle", "bottom", "left", "center", "right"] @@ -160,11 +160,11 @@ if align: _cls += " align-" + align if figclass: - _cls += " " + figclass + _cls += " " + escape_text(figclass) html = '<figure class="' + _cls + '"' if figwidth: - html += ' style="width:' + figwidth + '"' + html += ' style="width:' + escape_text(figwidth) + '"' return html + ">\n" + text + "</figure>\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/directives/include.py new/mistune-3.2.1/src/mistune/directives/include.py --- old/mistune-3.2.0/src/mistune/directives/include.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/directives/include.py 2026-05-03 16:30:25.000000000 +0200 @@ -30,7 +30,7 @@ dest = os.path.join(os.path.dirname(source_file), relpath) dest = os.path.normpath(dest) - if dest == source_file: + if os.path.abspath(dest) == os.path.abspath(source_file): return { "type": "block_error", "raw": "Could not include self: " + relpath, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/helpers.py new/mistune-3.2.1/src/mistune/helpers.py --- old/mistune-3.2.0/src/mistune/helpers.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/helpers.py 2026-05-03 16:30:25.000000000 +0200 @@ -19,8 +19,8 @@ LINK_TITLE_RE = re.compile( r"[ \t\n]+(" - r'"(?:\\' + PUNCTUATION + r'|[^"\x00])*"|' # "title" - r"'(?:\\" + PUNCTUATION + r"|[^'\x00])*'" # 'title' + r'"(?:\\' + PUNCTUATION + r'|[^"\\\x00])*"|' + r"'(?:\\" + PUNCTUATION + r"|[^'\\\x00])*'" r")" ) PAREN_END_RE = re.compile(r"\s*\)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/plugins/footnotes.py new/mistune-3.2.1/src/mistune/plugins/footnotes.py --- old/mistune-3.2.0/src/mistune/plugins/footnotes.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/plugins/footnotes.py 2026-05-03 16:30:25.000000000 +0200 @@ -2,7 +2,6 @@ from typing import TYPE_CHECKING, Any, Dict, List, Match, Union from ..core import BlockState -from ..helpers import LINK_LABEL from ..util import unikey if TYPE_CHECKING: @@ -14,16 +13,18 @@ __all__ = ["footnotes"] _PARAGRAPH_SPLIT = re.compile(r"\n{2,}") +# Like LINK_LABEL but disallows whitespace in footnote identifiers # https://michelf.ca/projects/php-markdown/extra/#footnotes +_FOOTNOTE_LABEL = r"(?:[^\\\[\]\s]|\\.){1,500}" REF_FOOTNOTE = ( r"^(?P<footnote_lead> {0,4})" - r"\[\^(?P<footnote_key>" + LINK_LABEL + r")]:[ \t\n]" + r"\[\^(?P<footnote_key>" + _FOOTNOTE_LABEL + r")]:[ \t\n]" r"(?P<footnote_text>[^\n]*(?:\n+|$)" r"(?:(?P=footnote_lead) {1,4}(?! )[^\n]*\n+)*" r")" ) -INLINE_FOOTNOTE = r"\[\^(?P<footnote_key>" + LINK_LABEL + r")\]" +INLINE_FOOTNOTE = r"\[\^(?P<footnote_key>" + _FOOTNOTE_LABEL + r")\]" def parse_inline_footnote(inline: "InlineParser", m: Match[str], state: "InlineState") -> int: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/plugins/math.py new/mistune-3.2.1/src/mistune/plugins/math.py --- old/mistune-3.2.0/src/mistune/plugins/math.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/plugins/math.py 2026-05-03 16:30:25.000000000 +0200 @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING, Match +from ..util import escape as escape_text if TYPE_CHECKING: from ..block_parser import BlockParser @@ -9,7 +10,7 @@ __all__ = ["math", "math_in_quote", "math_in_list"] BLOCK_MATH_PATTERN = r"^ {0,3}\$\$[ \t]*\n(?P<math_text>[\s\S]+?)\n\$\$[ \t]*$" -INLINE_MATH_PATTERN = r"\$(?!\s)(?P<math_text>.+?)(?!\s)\$" +INLINE_MATH_PATTERN = r"\$(?!\s)(?P<math_text>(?:[^$\\]|\\.)+?)(?!\s)\$" def parse_block_math(block: "BlockParser", m: Match[str], state: "BlockState") -> int: @@ -25,11 +26,11 @@ def render_block_math(renderer: "BaseRenderer", text: str) -> str: - return '<div class="math">$$\n' + text + "\n$$</div>\n" + return '<div class="math">$$\n' + escape_text(text) + "\n$$</div>\n" def render_inline_math(renderer: "BaseRenderer", text: str) -> str: - return r'<span class="math">\(' + text + r"\)</span>" + return r'<span class="math">\(' + escape_text(text) + r"\)</span>" def math(md: "Markdown") -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/renderers/html.py new/mistune-3.2.1/src/mistune/renderers/html.py --- old/mistune-3.2.0/src/mistune/renderers/html.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/renderers/html.py 2026-05-03 16:30:25.000000000 +0200 @@ -80,7 +80,7 @@ def image(self, text: str, url: str, title: Optional[str] = None) -> str: src = self.safe_url(url) - alt = escape_text(striptags(text)) + alt = striptags(text) s = '<img src="' + src + '" alt="' + alt + '"' if title: s += ' title="' + safe_entity(title) + '"' @@ -108,7 +108,7 @@ html = "<" + tag _id = attrs.get("id") if _id: - html += ' id="' + _id + '"' + html += ' id="' + escape_text(_id) + '"' return html + ">" + text + "</" + tag + ">\n" def blank_line(self) -> str: @@ -138,7 +138,7 @@ return html + "\n" def block_error(self, text: str) -> str: - return '<div class="error"><pre>' + text + "</pre></div>\n" + return '<div class="error"><pre>' + escape_text(text) + "</pre></div>\n" def list(self, text: str, ordered: bool, **attrs: Any) -> str: if ordered: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/src/mistune/toc.py new/mistune-3.2.1/src/mistune/toc.py --- old/mistune-3.2.0/src/mistune/toc.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/src/mistune/toc.py 2026-05-03 16:30:25.000000000 +0200 @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Tuple from .core import BlockState -from .util import striptags +from .util import striptags, escape if TYPE_CHECKING: from .markdown import Markdown @@ -89,7 +89,7 @@ s = "" levels: List[int] = [] for level, k, text in toc: - item = '<a href="#{}">{}</a>'.format(k, text) + item = '<a href="#{}">{}</a>'.format(escape(k), text) if not levels: s += "<li>" + item levels.append(level) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/tests/fixtures/__init__.py new/mistune-3.2.1/tests/fixtures/__init__.py --- old/mistune-3.2.0/tests/fixtures/__init__.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/tests/fixtures/__init__.py 2026-05-03 16:30:25.000000000 +0200 @@ -14,12 +14,12 @@ def load_ast(filename: str) -> Any: - with open(os.path.join(ROOT, "ast", filename)) as f: + with open(os.path.join(ROOT, "ast", filename), encoding="utf-8") as f: return json.load(f) def load_json(filename: str) -> Any: - with open(os.path.join(ROOT, filename)) as f: + with open(os.path.join(ROOT, filename), encoding="utf-8") as f: return json.load(f) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/tests/fixtures/fenced_toc.txt new/mistune-3.2.1/tests/fixtures/fenced_toc.txt --- old/mistune-3.2.0/tests/fixtures/fenced_toc.txt 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/tests/fixtures/fenced_toc.txt 2026-05-03 16:30:25.000000000 +0200 @@ -52,7 +52,7 @@ . <h1>H1</h1> <h2>H2</h2> -<div class="error"><pre>"max-level" option MUST be integer</pre></div> +<div class="error"><pre>"max-level" option MUST be integer</pre></div> ```````````````````````````````` ```````````````````````````````` example @@ -65,7 +65,7 @@ . <h1>H1</h1> <h2>H2</h2> -<div class="error"><pre>"max-level" option MUST be <= 3</pre></div> +<div class="error"><pre>"max-level" option MUST be <= 3</pre></div> ```````````````````````````````` ```````````````````````````````` example @@ -79,7 +79,7 @@ . <h1>H1</h1> <h2>H2</h2> -<div class="error"><pre>"min-level" option MUST be less than "max-level" option</pre></div> +<div class="error"><pre>"min-level" option MUST be less than "max-level" option</pre></div> ```````````````````````````````` ## Complex diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/tests/fixtures/math.txt new/mistune-3.2.1/tests/fixtures/math.txt --- old/mistune-3.2.0/tests/fixtures/math.txt 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/tests/fixtures/math.txt 2026-05-03 16:30:25.000000000 +0200 @@ -55,3 +55,9 @@ singleton set <span class="math">\(e_G\)</span>, because otherwise <span class="math">\(\exists a,b\in G\)</span> with <span class="math">\(a\neq b\)</span> such that <span class="math">\(f(a)=f(b)\)</span>.</p> ```````````````````````````````` + +```````````````````````````````` example +Escaped dollar sign in math: $x=\$$ +. +<p>Escaped dollar sign in math: <span class="math">\(x=\$\)</span></p> +```````````````````````````````` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/tests/fixtures/rst_toc.txt new/mistune-3.2.1/tests/fixtures/rst_toc.txt --- old/mistune-3.2.0/tests/fixtures/rst_toc.txt 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/tests/fixtures/rst_toc.txt 2026-05-03 16:30:25.000000000 +0200 @@ -50,7 +50,7 @@ . <h1>H1</h1> <h2>H2</h2> -<div class="error"><pre>"max-level" option MUST be integer</pre></div> +<div class="error"><pre>"max-level" option MUST be integer</pre></div> ```````````````````````````````` ```````````````````````````````` example @@ -61,7 +61,7 @@ . <h1>H1</h1> <h2>H2</h2> -<div class="error"><pre>"max-level" option MUST be <= 3</pre></div> +<div class="error"><pre>"max-level" option MUST be <= 3</pre></div> ```````````````````````````````` ```````````````````````````````` example @@ -73,7 +73,7 @@ . <h1>H1</h1> <h2>H2</h2> -<div class="error"><pre>"min-level" option MUST be less than "max-level" option</pre></div> +<div class="error"><pre>"min-level" option MUST be less than "max-level" option</pre></div> ```````````````````````````````` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/tests/test_commonmark.py new/mistune-3.2.1/tests/test_commonmark.py --- old/mistune-3.2.0/tests/test_commonmark.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/tests/test_commonmark.py 2026-05-03 16:30:25.000000000 +0200 @@ -18,6 +18,7 @@ # we don't support link title in (title) "links_496", "links_504", + "link_reference_definitions_202", # we don't support flanking delimiter run "emphasis_and_strong_emphasis_352", "emphasis_and_strong_emphasis_367", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mistune-3.2.0/tests/test_misc.py new/mistune-3.2.1/tests/test_misc.py --- old/mistune-3.2.0/tests/test_misc.py 2025-12-23 12:28:42.000000000 +0100 +++ new/mistune-3.2.1/tests/test_misc.py 2026-05-03 16:30:25.000000000 +0200 @@ -136,6 +136,19 @@ expected = "<h1>\u3000\u3000abc</h1>\n" self.assertEqual(result, expected) + def test_image_alt_no_double_encoding(self): + result = mistune.html("") + expected = '<p><img src="dogs.png" alt="dogs & cats" /></p>' + self.assertEqual(result.strip(), expected) + + result = mistune.html("") + expected = '<p><img src="dogs.png" alt="dogs > cats" /></p>' + self.assertEqual(result.strip(), expected) + + result = mistune.html('') + expected = '<p><img src="dogs.png" alt=""quoted"" /></p>' + self.assertEqual(result.strip(), expected) + def test_html_tag_text_following_list(self): md = mistune.create_markdown(escape=False, hard_wrap=True) result = md("foo\n- bar\n\ntable")
