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., ![**text**](url) 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>&quot;max-level&quot; 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>&quot;max-level&quot; option MUST be &lt;= 
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>&quot;min-level&quot; option MUST be less than 
&quot;max-level&quot; 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>&quot;max-level&quot; 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>&quot;max-level&quot; option MUST be &lt;= 
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>&quot;min-level&quot; option MUST be less than 
&quot;max-level&quot; 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("![dogs & cats](dogs.png)")
+        expected = '<p><img src="dogs.png" alt="dogs &amp; cats" /></p>'
+        self.assertEqual(result.strip(), expected)
+
+        result = mistune.html("![dogs > cats](dogs.png)")
+        expected = '<p><img src="dogs.png" alt="dogs &gt; cats" /></p>'
+        self.assertEqual(result.strip(), expected)
+
+        result = mistune.html('!["quoted"](dogs.png)')
+        expected = '<p><img src="dogs.png" alt="&quot;quoted&quot;" /></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")

Reply via email to