Skip to content

Commit

Permalink
🐛 fix parts defined in nested needs (#1265)
Browse files Browse the repository at this point in the history
parts should be assigned to the "closest" parent need
  • Loading branch information
chrisjsewell authored Sep 4, 2024
1 parent 3916cb7 commit b0d8e6c
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 3 deletions.
3 changes: 2 additions & 1 deletion sphinx_needs/roles/need_part.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from sphinx_needs.data import NeedsInfoType
from sphinx_needs.logging import get_logger, log_warning
from sphinx_needs.nodes import Need

log = get_logger(__name__)

Expand Down Expand Up @@ -121,6 +122,6 @@ def find_parts(node: nodes.Node) -> list[NeedPart]:
for child in node.children:
if isinstance(child, NeedPart):
found_nodes.append(child)
else:
elif not isinstance(child, Need): # parts in nested needs should be ignored
found_nodes += find_parts(child)
return found_nodes
115 changes: 115 additions & 0 deletions tests/__snapshots__/test_need_parts.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# name: test_doc_need_parts[test_app0]
dict({
'SP_TOO_001': dict({
'description': '''
The Tool awesome shall have a command line interface with following commands:

* :need_part:`(1)exit()`
* :need_part:`(2)start()`
* :need_part:`(awesome_id)blub()`


* :np:`unknown_id_1`
* :np:`unknown_id_2`

.. spec:: TEST_2
:id: TEST_2

Part in nested need: :need_part:`(nested_id)something`
''',
'docname': 'index',
'external_css': 'external_link',
'full_title': 'Command line interface',
'id': 'SP_TOO_001',
'layout': '',
'parent_needs_back': list([
'TEST_2',
]),
'parts': dict({
'1': dict({
'content': 'exit()',
'id': '1',
'links': list([
]),
'links_back': list([
]),
}),
'2': dict({
'content': 'start()',
'id': '2',
'links': list([
]),
'links_back': list([
]),
}),
'5DA': dict({
'content': 'unknown_id_1',
'id': '5DA',
'links': list([
]),
'links_back': list([
]),
}),
'7FF': dict({
'content': 'unknown_id_2',
'id': '7FF',
'links': list([
]),
'links_back': list([
]),
}),
'awesome_id': dict({
'content': 'blub()',
'id': 'awesome_id',
'links': list([
]),
'links_back': list([
]),
}),
}),
'section_name': 'NEED PARTS',
'sections': list([
'NEED PARTS',
]),
'status': 'implemented',
'tags': list([
'test',
'test2',
]),
'target_id': 'SP_TOO_001',
'title': 'Command line interface',
'type': 'spec',
'type_name': 'Specification',
}),
'TEST_2': dict({
'description': 'Part in nested need: :need_part:`(nested_id)something`',
'docname': 'index',
'external_css': 'external_link',
'full_title': 'TEST_2',
'id': 'TEST_2',
'layout': '',
'parent_need': 'SP_TOO_001',
'parent_needs': list([
'SP_TOO_001',
]),
'parts': dict({
'nested_id': dict({
'content': 'something',
'id': 'nested_id',
'links': list([
]),
'links_back': list([
]),
}),
}),
'section_name': 'NEED PARTS',
'sections': list([
'NEED PARTS',
]),
'target_id': 'TEST_2',
'title': 'TEST_2',
'type': 'spec',
'type_name': 'Specification',
}),
})
# ---
3 changes: 3 additions & 0 deletions tests/doc_test/doc_need_parts/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@
"style": "node",
},
]

needs_build_json = True
needs_json_remove_defaults = True
5 changes: 5 additions & 0 deletions tests/doc_test/doc_need_parts/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ NEED PARTS
* :np:`unknown_id_1`
* :np:`unknown_id_2`

.. spec:: TEST_2
:id: TEST_2

Part in nested need: :need_part:`(nested_id)something`


:need:`SP_TOO_001.1`

Expand Down
17 changes: 15 additions & 2 deletions tests/test_need_parts.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import json
import os
from pathlib import Path

import pytest
from sphinx.util.console import strip_colors


@pytest.mark.parametrize(
"test_app",
[{"buildername": "html", "srcdir": "doc_test/doc_need_parts"}],
[{"buildername": "html", "srcdir": "doc_test/doc_need_parts", "no_plantuml": True}],
indirect=True,
)
def test_doc_need_parts(test_app):
def test_doc_need_parts(test_app, snapshot):
app = test_app
app.build()

warnings = strip_colors(
app._warning.getvalue().replace(str(app.srcdir) + os.sep, "srcdir/")
).splitlines()
# print(warnings)
assert warnings == []

html = Path(app.outdir, "index.html").read_text()
assert (
'<span class="need-part" id="SP_TOO_001.1">exit()<a class="needs-id reference internal" '
Expand All @@ -24,3 +34,6 @@ def test_doc_need_parts(test_app):
'<em class="xref need">My custom link name (SP_TOO_001.awesome_id)</em>' in html
)
assert "SP_TOO_001" in html

data = json.loads(Path(app.outdir, "needs.json").read_text())
assert data["versions"][""]["needs"] == snapshot

0 comments on commit b0d8e6c

Please sign in to comment.