Skip to content

Commit a63e6f3

Browse files
authored
Fix edge-case crash in InlineProcessor
If an inlineprocessor returns an AtomicString (even though that is pointless, a plain string is atomic in that context), there can be an exception in 2 separate places. The added test case was crashing before this change.
1 parent f5b151a commit a63e6f3

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
* Remove legacy import needed only in Python 2 (#1403)
1818
* Fix typo that left the attribute `AdmonitionProcessor.content_indent` unset
1919
(#1404)
20+
* Fix edge-case crash in `InlineProcessor` with `AtomicString` (#1406).
2021
* Fix edge-case crash in `codehilite` with an empty `code` tag (#1405).
2122
* Improve and expand type annotations in the code base (#1401).
2223

markdown/treeprocessors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def linkText(text: str | None) -> None:
218218
text = data[strartIndex:index]
219219
linkText(text)
220220

221-
if not isString(node): # it's Element
221+
if not isinstance(node, str): # it's Element
222222
for child in [node] + list(node):
223223
if child.tail:
224224
if child.tail.strip():
@@ -304,7 +304,7 @@ def __applyPattern(
304304
if node is None:
305305
return data, True, end
306306

307-
if not isString(node):
307+
if not isinstance(node, str):
308308
if not isinstance(node.text, util.AtomicString):
309309
# We need to process current node too
310310
for child in [node] + list(node):

tests/test_apis.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import markdown
3131
import warnings
3232
from markdown.__main__ import parse_options
33+
from markdown import inlinepatterns
3334
from logging import DEBUG, WARNING, CRITICAL
3435
import yaml
3536
import tempfile
@@ -664,8 +665,8 @@ class testAtomicString(unittest.TestCase):
664665
""" Test that `AtomicStrings` are honored (not parsed). """
665666

666667
def setUp(self):
667-
md = markdown.Markdown()
668-
self.inlineprocessor = md.treeprocessors['inline']
668+
self.md = markdown.Markdown()
669+
self.inlineprocessor = self.md.treeprocessors['inline']
669670

670671
def testString(self):
671672
""" Test that a regular string is parsed. """
@@ -710,6 +711,26 @@ def testNestedAtomicString(self):
710711
'*to*</span> *test*</span> *with*</p></div>'
711712
)
712713

714+
def testInlineProcessorDoesntCrashWithWrongAtomicString(self):
715+
""" Test that an `AtomicString` returned from a Pattern doesn't cause a crash. """
716+
tree = etree.Element('div')
717+
p = etree.SubElement(tree, 'p')
718+
p.text = 'a marker c'
719+
self.md.inlinePatterns.register(
720+
_InlineProcessorThatReturnsAtomicString(r'marker', self.md), 'test', 100
721+
)
722+
new = self.inlineprocessor.run(tree)
723+
self.assertEqual(
724+
markdown.serializers.to_html_string(new),
725+
'<div><p>a &lt;b&gt;atomic&lt;/b&gt; c</p></div>'
726+
)
727+
728+
729+
class _InlineProcessorThatReturnsAtomicString(inlinepatterns.InlineProcessor):
730+
""" Return a simple text of `group(1)` of a Pattern. """
731+
def handleMatch(self, m, data):
732+
return markdown.util.AtomicString('<b>atomic</b>'), m.start(0), m.end(0)
733+
713734

714735
class TestConfigParsing(unittest.TestCase):
715736
def assertParses(self, value, result):

0 commit comments

Comments
 (0)