Skip to content

Commit 65666a6

Browse files
committed
fix: prevent mixed =/- chars in Setext-style headings (+tests)
Closes #1604
1 parent e7a0efb commit 65666a6

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

docs/changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ and this project adheres to the
1010
[Python Version Specification](https://packaging.python.org/en/latest/specifications/version-specifiers/).
1111
See the [Contributing Guide](contributing.md) for details.
1212

13+
## [Unreleased]
14+
15+
### Fixed
16+
17+
* Fix `SetextHeaderProcessor` regex to prevent mixed `=` and `-` chars in setext-style headers (#1604).
18+
19+
1320
## [3.10.2] - 2026-02-09
1421

1522
### Fixed

markdown/blockprocessors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ class SetextHeaderProcessor(BlockProcessor):
494494
""" Process Setext-style Headers. """
495495

496496
# Detect Setext-style header. Must be first 2 lines of block.
497-
RE = re.compile(r'^.*?\n[=-]+[ ]*(\n|$)', re.MULTILINE)
497+
RE = re.compile(r'^.*?\n(?:[=]+|[-]+)[ ]*(\n|$)', re.MULTILINE)
498498

499499
def test(self, parent: etree.Element, block: str) -> bool:
500500
return bool(self.RE.match(block))

tests/test_syntax/blocks/test_headers.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,58 @@ def test_setext_h2_followed_by_p(self):
109109

110110
# TODO: fix this
111111
# see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H1%0A%3D%3D%3D%3D%3D
112+
113+
def test_setext_mixed_chars_not_h1(self):
114+
"""Mixed = and - chars should not form a valid H1."""
115+
self.assertMarkdownRenders(
116+
self.dedent(
117+
"""
118+
This is not an H1
119+
=-
120+
"""
121+
),
122+
self.dedent(
123+
"""
124+
<p>This is not an H1
125+
=-</p>
126+
"""
127+
)
128+
)
129+
130+
def test_setext_mixed_chars_not_h2(self):
131+
"""Mixed - and = chars should not form a valid H2."""
132+
self.assertMarkdownRenders(
133+
self.dedent(
134+
"""
135+
This is not an H2
136+
-=
137+
"""
138+
),
139+
self.dedent(
140+
"""
141+
<p>This is not an H2
142+
-=</p>
143+
"""
144+
)
145+
)
146+
147+
def test_setext_mixed_multiple_chars(self):
148+
"""Multiple mixed = and - chars should not form a valid H1/H2."""
149+
self.assertMarkdownRenders(
150+
self.dedent(
151+
"""
152+
Not a Header
153+
=-=-
154+
"""
155+
),
156+
self.dedent(
157+
"""
158+
<p>Not a Header
159+
=-=-</p>
160+
"""
161+
)
162+
)
163+
112164
@unittest.skip('This is broken in Python-Markdown')
113165
def test_p_followed_by_setext_h1(self):
114166
self.assertMarkdownRenders(

0 commit comments

Comments
 (0)