Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ See the [Contributing Guide](contributing.md) for details.
### Fixed

* Fix an issue with excessive backtracking when matching inline code blocks (#1617).
* `md_in_html` now honors tags added to `Markdown.block_level_elements` after
the extension is loaded (#1246).

## [3.10.3] - 2026-07-30

Expand Down
18 changes: 13 additions & 5 deletions markdown/extensions/md_in_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ class HTMLExtractorExtra(HTMLExtractor):
"""

def __init__(self, md: Markdown, *args, **kwargs):
# All block-level tags.
self.block_level_tags = set(md.block_level_elements.copy())
# Block-level tags in which the content only gets span level parsing
self.span_tags = set(
['address', 'dd', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'legend', 'li', 'p', 'summary', 'td', 'th']
Expand All @@ -52,9 +50,19 @@ def __init__(self, md: Markdown, *args, **kwargs):

super().__init__(md, *args, **kwargs)

# Block-level tags in which the content gets parsed as blocks
self.block_tags = set(self.block_level_tags) - (self.span_tags | self.raw_tags | self.empty_tags)
self.span_and_blocks_tags = self.block_tags | self.span_tags
@property
def block_level_tags(self) -> set[str]:
# Read from the Markdown instance so tags registered after the
# extension is loaded (md.block_level_elements.append) are honored.
return set(self.md.block_level_elements)

@property
def block_tags(self) -> set[str]:
return set(self.block_level_tags) - (self.span_tags | self.raw_tags | self.empty_tags)

@property
def span_and_blocks_tags(self) -> set[str]:
return self.block_tags | self.span_tags

def reset(self):
"""Reset this instance. Loses all unprocessed data."""
Expand Down
30 changes: 30 additions & 0 deletions tests/test_syntax/extensions/test_md_in_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,36 @@ def test_noname_tag(self):
)
)

def test_registered_custom_element_is_block_level(self):
# Tags added to Markdown.block_level_elements after construction
# must still be treated as block-level HTML (#1246).
md = Markdown(extensions=['md_in_html'])
md.block_level_elements.append('a-b')
src = self.dedent(
"""
<a-b>

asdf

</a-b>
"""
)
self.assertEqual(md.convert(src), '<a-b>\n\nasdf\n\n</a-b>')

def test_registered_custom_element_markdown_attr(self):
md = Markdown(extensions=['md_in_html'])
md.block_level_elements.append('a-b')
src = self.dedent(
"""
<a-b markdown>

*asdf*

</a-b>
"""
)
self.assertEqual(md.convert(src), '<a-b>\n<p><em>asdf</em></p>\n</a-b>')


def load_tests(loader, tests, pattern):
""" Ensure `TestHTMLBlocks` doesn't get run twice by excluding it here. """
Expand Down
Loading