diff --git a/sphinx_needs/roles/need_part.py b/sphinx_needs/roles/need_part.py index 6384e738b..f40795380 100644 --- a/sphinx_needs/roles/need_part.py +++ b/sphinx_needs/roles/need_part.py @@ -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__) @@ -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 diff --git a/tests/__snapshots__/test_need_parts.ambr b/tests/__snapshots__/test_need_parts.ambr new file mode 100644 index 000000000..1dcec2ecf --- /dev/null +++ b/tests/__snapshots__/test_need_parts.ambr @@ -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', + }), + }) +# --- diff --git a/tests/doc_test/doc_need_parts/conf.py b/tests/doc_test/doc_need_parts/conf.py index 1b74e151a..00c80893f 100644 --- a/tests/doc_test/doc_need_parts/conf.py +++ b/tests/doc_test/doc_need_parts/conf.py @@ -30,3 +30,6 @@ "style": "node", }, ] + +needs_build_json = True +needs_json_remove_defaults = True diff --git a/tests/doc_test/doc_need_parts/index.rst b/tests/doc_test/doc_need_parts/index.rst index b491cc784..1d8b2d70f 100644 --- a/tests/doc_test/doc_need_parts/index.rst +++ b/tests/doc_test/doc_need_parts/index.rst @@ -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` diff --git a/tests/test_need_parts.py b/tests/test_need_parts.py index e8a3c8c69..ba0b94795 100644 --- a/tests/test_need_parts.py +++ b/tests/test_need_parts.py @@ -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 ( 'exit()My custom link name (SP_TOO_001.awesome_id)' in html ) assert "SP_TOO_001" in html + + data = json.loads(Path(app.outdir, "needs.json").read_text()) + assert data["versions"][""]["needs"] == snapshot