https://github.com/python/cpython/commit/ed370d3337c1ac4f7295b444a4807c0b72287608
commit: ed370d3337c1ac4f7295b444a4807c0b72287608
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-04T15:05:07+03:00
summary:
gh-135661: Fix abrupt closing of empty comment in HTMLParser (GH-153007)
An abruptly closed empty comment ("<!-->" or "<!--->") no longer extends
up to a later "-->" in the same feed() call.
test_htmlparser now also feeds each string source as a single chunk, in
addition to one character at a time, to exercise different input buffering.
Co-authored-by: Claude Opus 4.8 <[email protected]>
files:
A Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst
M Lib/html/parser.py
M Lib/test/test_htmlparser.py
diff --git a/Lib/html/parser.py b/Lib/html/parser.py
index 80fb8c3f929f6b6..38ddf9ef442d368 100644
--- a/Lib/html/parser.py
+++ b/Lib/html/parser.py
@@ -387,9 +387,11 @@ def parse_html_declaration(self, i):
def parse_comment(self, i, report=True):
rawdata = self.rawdata
assert rawdata.startswith('<!--', i), 'unexpected call to
parse_comment()'
- match = commentclose.search(rawdata, i+4)
+ # An empty comment is abruptly closed by the first ">" or "->",
+ # taking priority over a later "-->" or "--!>" close.
+ match = commentabruptclose.match(rawdata, i+4)
if not match:
- match = commentabruptclose.match(rawdata, i+4)
+ match = commentclose.search(rawdata, i+4)
if not match:
return -1
if report:
diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py
index e4eff1ea17a670b..6b7624f11505d92 100644
--- a/Lib/test/test_htmlparser.py
+++ b/Lib/test/test_htmlparser.py
@@ -116,6 +116,11 @@ def _run_check(self, source, expected_events,
*, collector=None, convert_charrefs=False):
if collector is None:
collector = self.get_collector(convert_charrefs=convert_charrefs)
+ if isinstance(source, str):
+ # Also feed the whole string at once, not just character by
+ # character (below), to exercise different input buffering.
+ self._run_check([source], expected_events,
+ convert_charrefs=convert_charrefs)
parser = collector
for s in source:
parser.feed(s)
@@ -593,6 +598,9 @@ def test_comments(self):
'<!-- <!-- nested --> -->'
'<!--<!-->'
'<!--<!--!>'
+ # abruptly closed empty comment must not swallow later text
+ '<!-->x-->'
+ '<!--->y-->'
)
expected = [('comment', " I'm a valid comment "),
('comment', 'me too!'),
@@ -613,6 +621,8 @@ def test_comments(self):
('comment', ' <!-- nested '), ('data', ' -->'),
('comment', '<!'),
('comment', '<!'),
+ ('comment', ''), ('data', 'x-->'),
+ ('comment', ''), ('data', 'y-->'),
]
self._run_check(html, expected)
diff --git
a/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst
b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst
new file mode 100644
index 000000000000000..26a912a6f3a1949
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst
@@ -0,0 +1,3 @@
+Fix :class:`html.parser.HTMLParser`: an abruptly closed empty comment
+(``<!-->`` or ``<!--->``) no longer extends up to a later ``-->`` in the same
+:meth:`~html.parser.HTMLParser.feed` call.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]