diff --git a/CHANGES b/CHANGES index 578db5cd0b8..c807f07f556 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,9 @@ Features added Bugs fixed ---------- +* #11091: Fix ``util.nodes.apply_source_workaround`` for ``literal_block`` nodes + with no source information in the node or the node's parents. + Testing -------- diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 9fc484086d5..18dd94f4616 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -2,6 +2,7 @@ from __future__ import annotations +import contextlib import re import unicodedata from typing import TYPE_CHECKING, Any, Callable, Iterable @@ -152,7 +153,8 @@ def apply_source_workaround(node: Element) -> None: # workaround: literal_block under bullet list (#4913) if isinstance(node, nodes.literal_block) and node.source is None: - node.source = get_node_source(node) + with contextlib.suppress(ValueError): + node.source = get_node_source(node) # workaround: recommonmark-0.2.0 doesn't set rawsource attribute if not node.rawsource: diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index 721851f92da..6c2e329a979 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -11,8 +11,8 @@ from docutils.utils import new_document from sphinx.transforms import ApplySourceWorkaround -from sphinx.util.nodes import (NodeMatcher, clean_astext, extract_messages, make_id, - split_explicit_title) +from sphinx.util.nodes import (NodeMatcher, apply_source_workaround, clean_astext, + extract_messages, make_id, split_explicit_title) def _transform(doctree): @@ -226,3 +226,23 @@ def test_make_id_sequential(app): ) def test_split_explicit_target(title, expected): assert expected == split_explicit_title(title) + + +def test_apply_source_workaround_literal_block_no_source(): + """Regression test for #11091. + + Test that apply_source_workaround doesn't raise. + """ + literal_block = nodes.literal_block('', '') + list_item = nodes.list_item('', literal_block) + bullet_list = nodes.bullet_list('', list_item) + + assert literal_block.source is None + assert list_item.source is None + assert bullet_list.source is None + + apply_source_workaround(literal_block) + + assert literal_block.source is None + assert list_item.source is None + assert bullet_list.source is None