Skip to content

Commit 4faedec

Browse files
authored
👌 Improve removal of hidden need nodes (#1013)
This commit improves on the current logic (from #995) and moves it to occur earlier in the build process, directly after the need location has been analysed (i.e. once it is no longer necessary).
1 parent 03bd887 commit 4faedec

File tree

6 files changed

+99
-86
lines changed

6 files changed

+99
-86
lines changed

‎docs/configuration.rst

+44-46
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,50 @@ Example:
17921792
The created ``needs.json`` file gets stored in the ``outdir`` of the current builder.
17931793
So if ``html`` is used as builder, the final location is e.g. ``_build/html/needs.json``.
17941794
1795+
1796+
.. _needs_build_json_per_id:
1797+
1798+
needs_build_json_per_id
1799+
~~~~~~~~~~~~~~~~~~~~~~~
1800+
1801+
.. versionadded:: 1.4.0
1802+
1803+
Builds list json files for each need. The name of each file is the ``id`` of need.
1804+
This option works like :ref:`needs_build_json`.
1805+
1806+
Default: False
1807+
1808+
Example:
1809+
1810+
.. code-block:: python
1811+
1812+
needs_build_json_per_id = False
1813+
1814+
.. hint::
1815+
1816+
The created single json file per need, located in :ref:`needs_build_json_per_id_path` folder, e.g ``_build/needs_id/abc_432.json``
1817+
1818+
.. _needs_build_json_per_id_path:
1819+
1820+
needs_build_json_per_id_path
1821+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1822+
1823+
.. versionadded:: 1.4.0
1824+
1825+
This option sets the location of the set of ``needs.json`` for every needs-id.
1826+
1827+
Default value: ``needs_id``
1828+
1829+
Example:
1830+
1831+
.. code-block:: python
1832+
1833+
needs_build_json_per_id_path = "needs_id"
1834+
1835+
.. hint::
1836+
1837+
The created ``needs_id`` folder gets stored in the ``outdir`` of the current builder. The final location is e.g. ``_build/needs_id``
1838+
17951839
.. _needs_build_needumls:
17961840
17971841
needs_build_needumls
@@ -2289,49 +2333,3 @@ If true, need options like status, tags or links are collapsed and shown only af
22892333
Default value: True
22902334
22912335
Can be overwritten for each single need by setting :ref:`need_collapse`.
2292-
2293-
.. _needs_build_json_per_id:
2294-
2295-
needs_build_json_per_id
2296-
~~~~~~~~~~~~~~~~~~~~~~~
2297-
2298-
.. versionadded:: 1.4.0
2299-
2300-
Builds list json files for each need. The name of each file is the ``id`` of need.
2301-
This option works like :ref:`needs_build_json`.
2302-
2303-
Default: False
2304-
2305-
Example:
2306-
2307-
.. code-block:: python
2308-
2309-
needs_build_json_per_id = False
2310-
2311-
.. hint::
2312-
2313-
The created single json file per need, located in :ref:`needs_build_json_per_id_path` folder, e.g ``_build/needs_id/abc_432.json``
2314-
2315-
.. _needs_build_json_per_id_path:
2316-
2317-
needs_build_json_per_id_path
2318-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2319-
2320-
.. versionadded:: 1.4.0
2321-
2322-
This option sets the location of the set of ``needs.json`` for every needs-id.
2323-
2324-
Default value: ``needs_id``
2325-
2326-
Example:
2327-
2328-
.. code-block:: python
2329-
2330-
needs_build_json_per_id_path = "needs_id"
2331-
2332-
.. hint::
2333-
2334-
The created ``needs_id`` folder gets stored in the ``outdir`` of the current builder. The final location is e.g. ``_build/needs_id``
2335-
2336-
2337-

‎docs/contributing.rst

+10-9
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,14 @@ The following is an outline of the build events which this extension adds to the
203203
- Start process timing, if enabled (``prepare_env``)
204204
- Load external needs (``load_external_needs``)
205205

206-
#. For all removed and changed documents (``env-before-read-docs`` event):
206+
#. For all removed and changed documents (``env-purge-doc`` event):
207207

208208
- Remove all cached need items that originate from the document (``purge_needs``)
209209

210210
#. For changed documents (``doctree-read`` event, priority 880 of transforms)
211211

212-
- Determine and add data on containing sections and parents to needs (``add_sections``)
212+
- Determine and add data on parent sections and needs(``analyse_need_locations``)
213+
- Remove ``Need`` nodes marked as ``hidden`` (``analyse_need_locations``)
213214

214215
#. When building in parallel mode (``env-merge-info`` event), merge ``BuildEnvironment`` data (``merge_data``)
215216

@@ -223,7 +224,7 @@ The following is an outline of the build events which this extension adds to the
223224

224225
#. For all changed documents, or their dependants (``doctree-resolved``)
225226

226-
- Replace all ```Needextract``` nodes with a list of the collected ``Need`` (``process_creator``)
227+
- Replace all ``Needextract`` nodes with a list of the collected ``Need`` (``process_creator``)
227228
- Remove all ``Need`` nodes, if ``needs_include_needs`` is ``True`` (``process_need_nodes``)
228229
- Call dynamic functions, set as values on the need data items and replace them with their return values (``process_need_nodes -> resolve_dynamic_values``)
229230
- Replace needs data variant values (``process_need_nodes -> resolve_variants_options``)
@@ -232,15 +233,15 @@ The following is an outline of the build events which this extension adds to the
232233
- Process constraints, for each ``Need`` node (``process_need_nodes -> process_constraints``)
233234
- Perform all modifications on need data items, due to ``Needextend`` nodes (``process_need_nodes -> process_needextend``)
234235
- Format each ``Need`` node to give the desired visual output (``process_need_nodes -> print_need_nodes``)
235-
- Process all need specific nodes, replacing them with the desired visual output (``process_creator``)
236-
- Remove ``Need`` nodes marked as ``hidden`` (``remove_hidden_needs``)
236+
- Process all other need specific nodes, replacing them with the desired visual output (``process_creator``)
237237

238238
#. At the end of the build (``build-finished`` event)
239239

240-
- Call all user defined need data checks, a.k.a warnings (``process_warnings``)
241-
- Write the ``needs.json`` to the output folder (``build_needs_json``)
242-
- Write all required UML files to the output file (``build_needumls_pumls``)
243-
- Print process timing, if enabled (``process_timing``)
240+
- Call all user defined need data checks, a.k.a `needs_warnings` (``process_warnings``)
241+
- Write the ``needs.json`` to the output folder, if `needs_build_json = True` (``build_needs_json``)
242+
- Write the ``needs.json`` per ID to the output folder, if `needs_build_json_per_id = True` (``build_needs_id_json``)
243+
- Write all UML files to the output folder, if `needs_build_needumls = True` (``build_needumls_pumls``)
244+
- Print process timing, if `needs_debug_measurement = True` (``process_timing``)
244245

245246
.. Include our contributors and maintainers.
246247
.. include:: ../AUTHORS

‎sphinx_needs/api/need.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ def run():
337337
"external_css": external_css or "external_link",
338338
"is_modified": False, # needed by needextend
339339
"modifications": 0, # needed by needextend
340+
# these are set later in the analyse_need_locations transform
341+
"sections": [],
342+
"section_name": "",
343+
"signature": "",
344+
"parent_needs": [],
345+
"parent_need": "",
340346
}
341347
needs_extra_option_names = list(NEEDS_CONFIG.extra_options)
342348
_merge_extra_options(needs_info, kwargs, needs_extra_option_names)
@@ -436,8 +442,9 @@ def run():
436442
node_need.line = needs_info["lineno"]
437443

438444
if needs_info["hide"]:
439-
# add node to doctree, so we can later compute the containing section(s)
440-
# (for use with section filters)
445+
# still add node to doctree,
446+
# so we can later compute its relative location in the document
447+
# (see analyse_need_locations function)
441448
node_need["hidden"] = True
442449
return [node_need]
443450

‎sphinx_needs/data.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class NeedsInfoType(NeedsBaseDataType):
166166
# additional source information
167167
doctype: str
168168
"""Type of the document where the need is defined, e.g. '.rst'"""
169-
# set in add_sections transform
169+
# set in analyse_need_locations transform
170170
sections: list[str]
171171
section_name: str
172172
"""Simply the first section"""

‎sphinx_needs/directives/need.py

+21-14
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,23 @@ def purge_needs(app: Sphinx, env: BuildEnvironment, docname: str) -> None:
285285
del needs[need_id]
286286

287287

288-
def add_sections(app: Sphinx, doctree: nodes.document) -> None:
289-
"""Add section titles to the needs as additional attributes that can
290-
be used in tables and filters"""
288+
def analyse_need_locations(app: Sphinx, doctree: nodes.document) -> None:
289+
"""Determine the location of each need in the doctree,
290+
relative to its parent section(s) and need(s).
291+
292+
This data is added to the need's data stored in the Sphinx environment,
293+
so that it can be used in tables and filters.
294+
295+
Once this data is determined, any hidden needs
296+
(i.e. ones that should not be rendered in the output)
297+
are removed from the doctree.
298+
"""
291299
builder = unwrap(app.builder)
292300
env = unwrap(builder.env)
293301

294302
needs = SphinxNeedsData(env).get_or_create_needs()
295303

304+
hidden_needs: List[Need] = []
296305
for need_node in doctree.findall(Need):
297306
need_id = need_node["refid"]
298307
need_info = needs[need_id]
@@ -329,6 +338,15 @@ def add_sections(app: Sphinx, doctree: nodes.document) -> None:
329338
need_info["parent_needs"] = parent_needs
330339
need_info["parent_need"] = parent_needs[0]
331340

341+
if need_node.get("hidden"):
342+
hidden_needs.append(need_node)
343+
344+
# now we have gathered all the information we need,
345+
# we can remove the hidden needs from the doctree
346+
for need_node in hidden_needs:
347+
if need_node.parent is not None:
348+
need_node.parent.remove(need_node) # type: ignore[attr-defined]
349+
332350

333351
def previous_sibling(node: nodes.Node) -> Optional[nodes.Node]:
334352
"""Return preceding sibling node or ``None``."""
@@ -389,8 +407,6 @@ def process_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) -
389407
# Used to store needs in the docs, which are needed again later
390408
found_needs_nodes = []
391409
for node_need in doctree.findall(Need):
392-
if node_need.get("hidden"):
393-
continue
394410
need_id = node_need.attributes["ids"][0]
395411
found_needs_nodes.append(node_need)
396412
need_data = needs[need_id]
@@ -544,15 +560,6 @@ def _fix_list_dyn_func(list: List[str]) -> List[str]:
544560
return new_list
545561

546562

547-
def remove_hidden_needs(app: Sphinx, doctree: nodes.document, fromdocname: str) -> None:
548-
"""Remove hidden needs from the doctree, before it is rendered."""
549-
if fromdocname not in SphinxNeedsData(app.env).get_or_create_docs().get("all", []):
550-
return
551-
for node_need in list(doctree.findall(Need)):
552-
if node_need.get("hidden"):
553-
node_need.parent.remove(node_need) # type: ignore
554-
555-
556563
#####################
557564
# Visitor functions #
558565
#####################

‎sphinx_needs/needs.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,13 @@
2929
from sphinx_needs.directives.need import (
3030
Need,
3131
NeedDirective,
32-
add_sections,
32+
analyse_need_locations,
3333
html_depart,
3434
html_visit,
3535
latex_depart,
3636
latex_visit,
3737
process_need_nodes,
3838
purge_needs,
39-
remove_hidden_needs,
4039
)
4140
from sphinx_needs.directives.needbar import Needbar, NeedbarDirective, process_needbar
4241
from sphinx_needs.directives.needextend import Needextend, NeedextendDirective
@@ -214,15 +213,23 @@ def setup(app: Sphinx) -> Dict[str, Any]:
214213
# EVENTS
215214
########################################################################
216215
# Make connections to events
217-
app.connect("env-purge-doc", purge_needs)
218216
app.connect("config-inited", load_config)
217+
app.connect("config-inited", check_configuration)
218+
219219
app.connect("env-before-read-docs", prepare_env)
220220
app.connect("env-before-read-docs", load_external_needs)
221-
app.connect("config-inited", check_configuration)
222-
# app.connect("doctree-resolved", add_sections)
223-
app.connect("doctree-read", add_sections)
221+
222+
app.connect("env-purge-doc", purge_needs)
223+
224+
app.connect("doctree-read", analyse_need_locations)
225+
224226
app.connect("env-merge-info", merge_data)
225227

228+
app.connect("env-updated", install_lib_static_files)
229+
app.connect("env-updated", install_permalink_file)
230+
# This should be called last, so that need-styles can override styles from used libraries
231+
app.connect("env-updated", install_styles_static_files)
232+
226233
# There is also the event doctree-read.
227234
# But it looks like in this event no references are already solved, which
228235
# makes trouble in our code.
@@ -233,19 +240,12 @@ def setup(app: Sphinx) -> Dict[str, Any]:
233240
app.connect("doctree-resolved", process_creator(NODE_TYPES_PRIO, "needextract"), priority=100)
234241
app.connect("doctree-resolved", process_need_nodes)
235242
app.connect("doctree-resolved", process_creator(NODE_TYPES))
236-
app.connect("doctree-resolved", remove_hidden_needs, priority=1000)
237243

238244
app.connect("build-finished", process_warnings)
239245
app.connect("build-finished", build_needs_json)
246+
app.connect("build-finished", build_needs_id_json)
240247
app.connect("build-finished", build_needumls_pumls)
241248
app.connect("build-finished", debug.process_timing)
242-
app.connect("env-updated", install_lib_static_files)
243-
app.connect("env-updated", install_permalink_file)
244-
245-
#
246-
app.connect("build-finished", build_needs_id_json)
247-
# This should be called last, so that need-styles can override styles from used libraries
248-
app.connect("env-updated", install_styles_static_files)
249249

250250
# Be sure Sphinx-Needs config gets erased before any events or external API calls get executed.
251251
# So never but this inside an event.

0 commit comments

Comments
 (0)