Skip to content

Commit 6f788ef

Browse files
committed
exclude needs under only directive if required (useblocks#1103)
1 parent 73b961e commit 6f788ef

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

sphinx_needs/directives/need.py

+13
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ def analyse_need_locations(app: Sphinx, doctree: nodes.document) -> None:
340340
if need_node.get("hidden"):
341341
hidden_needs.append(need_node)
342342

343+
if need_node_excluded_by_only_directive(env, need_node):
344+
hidden_needs.append(need_node)
345+
343346
# now we have gathered all the information we need,
344347
# we can remove the hidden needs from the doctree
345348
for need_node in hidden_needs:
@@ -356,6 +359,16 @@ def previous_sibling(node: nodes.Node) -> Optional[nodes.Node]:
356359
return node.parent[i - 1] if i > 0 else None # type: ignore
357360

358361

362+
def need_node_excluded_by_only_directive(env: BuildEnvironment, node: nodes.Node) -> bool:
363+
"""Return True if the node is under an "only" directive that shall be excluded given to the current tags"""
364+
if hasattr(node.parent, "tagname") and node.parent.tagname == "only":
365+
# note that we only check for a direct parent,
366+
# maybe we should look recursively until we reach the root of the document
367+
only_tags = node.parent.attributes.get("expr", "")
368+
return env.app.builder.tags.eval_condition(only_tags)
369+
return False
370+
371+
359372
@profile("NEEDS_POST_PROCESS")
360373
@measure_time("need_post_process")
361374
def post_process_needs_data(app: Sphinx) -> None:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extensions = ["sphinx_needs"]
2+
3+
# also build the needs.json as some needs shall be hidden in it too
4+
needs_build_json = True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Only directive Test
2+
=====================
3+
4+
.. only:: tag_a
5+
6+
.. req:: req_001
7+
8+
I shall not appear if not running tag_a
9+
10+
.. only:: tag_b
11+
12+
.. req:: req_002
13+
14+
I shall not appear if not running tag_b
15+
16+
.. only:: tag_a or tag_b
17+
18+
.. req:: req_003
19+
20+
I shall not appear if not running either tag_a or tag_b
21+
22+
23+
.. req:: req_004
24+
25+
I shall always appear
26+
27+
28+
.. needtable::
29+
types: req
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import json
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
7+
@pytest.mark.parametrize(
8+
"test_app",
9+
[
10+
{"buildername": "html", "srcdir": "doc_test/doc_directive_only", "tags": ["tag_a"]},
11+
],
12+
indirect=True,
13+
)
14+
def test_need_excluded_under_only_a(test_app):
15+
app = test_app
16+
app.build()
17+
html = Path(app.outdir, "index.html").read_text()
18+
needs_list = json.loads(Path(app.outdir, "needs.json").read_text())
19+
20+
assert "req_001" in html
21+
assert "req_002" not in html
22+
assert "req_003" in html
23+
assert "req_004" in html
24+
25+
assert "req_001" in needs_list
26+
assert "req_002" not in needs_list
27+
assert "req_003" in needs_list
28+
assert "req_004" in needs_list
29+
30+
31+
@pytest.mark.parametrize(
32+
"test_app",
33+
[
34+
{"buildername": "html", "srcdir": "doc_test/doc_directive_only", "tags": ["tag_a"]},
35+
],
36+
indirect=True,
37+
)
38+
def test_need_excluded_under_only_b(test_app):
39+
app = test_app
40+
app.build()
41+
html = Path(app.outdir, "index.html").read_text()
42+
needs_list = json.loads(Path(app.outdir, "needs.json").read_text())
43+
44+
assert "req_001" not in html
45+
assert "req_002" in html
46+
assert "req_003" in html
47+
assert "req_004" in html
48+
49+
assert "req_001" not in needs_list
50+
assert "req_002" in needs_list
51+
assert "req_003" in needs_list
52+
assert "req_004" in needs_list
53+
54+
55+
@pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_directive_only"}], indirect=True)
56+
def test_need_excluded_under_only_no_tag(test_app):
57+
app = test_app
58+
app.build()
59+
html = Path(app.outdir, "index.html").read_text()
60+
needs_list = json.loads(Path(app.outdir, "needs.json").read_text())
61+
62+
assert "req_001" not in html
63+
assert "req_002" not in html
64+
assert "req_003" not in html
65+
assert "req_004" in html
66+
67+
assert "req_001" not in needs_list
68+
assert "req_002" not in needs_list
69+
assert "req_003" not in needs_list
70+
assert "req_004" in needs_list

0 commit comments

Comments
 (0)