Skip to content

Commit 9b14297

Browse files
functions: Fix broken parent-child node relationships
The find_and_replace_node_content function breaks parent-child node relationships since it does not go through the docutils tools for assigning node children. The Element class in docutils will [1] iterate over each added child; we'll mimic that here. (We can't use the Element variant since we're only guaranteed to be of type Node, which doesn't have these helper functions, unfortunately.) Notably, the sphinxcontrib-spelling [2] extension is broken by this broken parent-child relationship since if something is misspelled it tries to identify which source line was impacted. When a node is added as a child, setup_child(...) [3] code fixes up the source/line location with the parent's information if needed. A test has been added at the top-level which covers every single test run by adding a build hook into the "doctree-resolved" hook. This test is fairly simple - check each node (outside of the top node) and validate that it has a parent assigned. [1] https://github.com/docutils/docutils/blob/4e912fe000b1b6dc1466c0ad1c3d1787d40fd96d/docutils/docutils/nodes.py#L788-L794 [2] https://pypi.org/project/sphinxcontrib-spelling/ [3] https://github.com/docutils/docutils/blob/4e912fe000b1b6dc1466c0ad1c3d1787d40fd96d/docutils/docutils/nodes.py#L150-L157
1 parent fbcfbab commit 9b14297

2 files changed

Lines changed: 13 additions & 0 deletions

File tree

‎sphinx_needs/functions/functions.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ def find_and_replace_node_content(
257257
new_child = find_and_replace_node_content(child, env, need)
258258
new_children.append(new_child)
259259
node.children = new_children
260+
for subchild in node.children:
261+
node.setup_child(subchild)
260262
else:
261263
node = nodes.Text(new_text)
262264
return node
@@ -269,6 +271,8 @@ def find_and_replace_node_content(
269271
new_child = find_and_replace_node_content(child, env, need)
270272
new_children.append(new_child)
271273
node.children = new_children
274+
for subchild in node.children:
275+
node.setup_child(subchild)
272276
return node
273277

274278

‎tests/conftest.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ def sphinx_test_tempdir(request) -> path:
254254
return sphinx_test_tempdir
255255

256256

257+
def test_check_parent_child(app: Sphinx, doctree: document, docname: str):
258+
for idx, node in enumerate(doctree.findall()):
259+
if idx == 0:
260+
continue
261+
assert node.parent
262+
263+
257264
@pytest.fixture(scope="function")
258265
def test_app(make_app, sphinx_test_tempdir, request):
259266
"""
@@ -330,6 +337,8 @@ def test_app(make_app, sphinx_test_tempdir, request):
330337
# ``test_js`` behaves like a method.
331338
app.test_js = test_js.__get__(app, Sphinx)
332339

340+
app.connect("doctree-resolved", test_check_parent_child, priority=999)
341+
333342
yield app
334343

335344
app.cleanup()

0 commit comments

Comments
 (0)