Skip to content

Commit

Permalink
🔧 Move data from global env to individual nodes (#1237)
Browse files Browse the repository at this point in the history
This PR changes logic for nearly all directives that require post-processing, so that all information coming from the directive is stored directly on the node in the doctree, rather than centrally in the `BuildEnvironment`.

It is unnecessary to store this data centrally and it increases complexity (having to keep it in-sync) and the size of the `BuildEnvironment`.

The only node I have not done this for is `needuml`, since there is some additional interplay between the `arch` need field, which I do not fully understand yet.
  • Loading branch information
chrisjsewell authored Aug 26, 2024
1 parent 3fe2dd4 commit 0e210b8
Show file tree
Hide file tree
Showing 12 changed files with 63 additions and 178 deletions.
110 changes: 0 additions & 110 deletions sphinx_needs/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,17 +736,6 @@ def get_or_create_services(self) -> ServiceManager:
self.env.app.needs_services = ServiceManager(self.env.app)
return self.env.app.needs_services

def get_or_create_bars(self) -> dict[str, NeedsBarType]:
"""Get all bar charts, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needbar
except AttributeError:
self.env.need_all_needbar = {}
return self.env.need_all_needbar

def get_or_create_extends(self) -> dict[str, NeedsExtendType]:
"""Get all need modifications, mapped by ID.
Expand All @@ -758,96 +747,6 @@ def get_or_create_extends(self) -> dict[str, NeedsExtendType]:
self.env.need_all_needextend = {}
return self.env.need_all_needextend

def get_or_create_extracts(self) -> dict[str, NeedsExtractType]:
"""Get all need extractions, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needextracts
except AttributeError:
self.env.need_all_needextracts = {}
return self.env.need_all_needextracts

def _get_or_create_filters(self) -> dict[str, _NeedsFilterType]:
"""Get all need filters, mapped by ID.
.. deprecated:: 0.2.0
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needfilters
except AttributeError:
self.env.need_all_needfilters = {}
return self.env.need_all_needfilters

def get_or_create_flows(self) -> dict[str, NeedsFlowType]:
"""Get all need flow charts, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needflows
except AttributeError:
self.env.need_all_needflows = {}
return self.env.need_all_needflows

def get_or_create_gantts(self) -> dict[str, NeedsGanttType]:
"""Get all need gantt charts, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needgantts
except AttributeError:
self.env.need_all_needgantts = {}
return self.env.need_all_needgantts

def get_or_create_lists(self) -> dict[str, NeedsListType]:
"""Get all need gantt charts, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needlists
except AttributeError:
self.env.need_all_needlists = {}
return self.env.need_all_needlists

def get_or_create_pies(self) -> dict[str, NeedsPieType]:
"""Get all need gantt charts, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needpie
except AttributeError:
self.env.need_all_needpie = {}
return self.env.need_all_needpie

def get_or_create_sequences(self) -> dict[str, NeedsSequenceType]:
"""Get all need sequence diagrams, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needsequences
except AttributeError:
self.env.need_all_needsequences = {}
return self.env.need_all_needsequences

def get_or_create_tables(self) -> dict[str, NeedsTableType]:
"""Get all need tables, mapped by ID.
This is lazily created and cached in the environment.
"""
try:
return self.env.need_all_needtables
except AttributeError:
self.env.need_all_needtables = {}
return self.env.need_all_needtables

def get_or_create_umls(self) -> dict[str, NeedsUmlType]:
"""Get all need uml diagrams, mapped by ID.
Expand Down Expand Up @@ -924,14 +823,5 @@ def _merge(name: str, is_complex_dict: bool = False) -> None:
)

_merge("needs_all_docs", is_complex_dict=True)
_merge("need_all_needbar")
_merge("need_all_needextend")
_merge("need_all_needextracts")
_merge("need_all_needfilters")
_merge("need_all_needflows")
_merge("need_all_needgantts")
_merge("need_all_needlists")
_merge("need_all_needpie")
_merge("need_all_needsequences")
_merge("need_all_needtables")
_merge("needs_all_needumls")
17 changes: 7 additions & 10 deletions sphinx_needs/directives/needbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from sphinx.application import Sphinx

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import SphinxNeedsData
from sphinx_needs.data import NeedsBarType, SphinxNeedsData
from sphinx_needs.filter_common import FilterBase, filter_needs, prepare_need_list
from sphinx_needs.logging import get_logger
from sphinx_needs.utils import (
Expand Down Expand Up @@ -127,9 +127,7 @@ def run(self) -> Sequence[nodes.Node]:
transpose = "transpose" in self.options
horizontal = "horizontal" in self.options

# 2. Stores infos for needbar
data = SphinxNeedsData(self.env).get_or_create_bars()
data[targetid] = {
data_attributes: NeedsBarType = {
"docname": env.docname,
"lineno": self.lineno,
"target_id": targetid,
Expand All @@ -155,11 +153,11 @@ def run(self) -> Sequence[nodes.Node]:
"text_color": text_color,
}

add_doc(env, env.docname)

bar_node = Needbar("")
bar_node = Needbar("", **data_attributes)
self.set_source_info(bar_node)

add_doc(env, env.docname)

return [targetnode, bar_node]


Expand Down Expand Up @@ -202,8 +200,7 @@ def process_needbar(
remove_node_from_tree(node)
continue

id = node.attributes["ids"][0]
current_needbar = needs_data.get_or_create_bars()[id]
current_needbar: NeedsBarType = node.attributes

if matplotlib is None:
message = "Matplotlib missing for needbar plot"
Expand Down Expand Up @@ -473,7 +470,7 @@ def process_needbar(
# 9. final storage

# We need to calculate an unique bar-image file name
hash_value = hashlib.sha256(id.encode()).hexdigest()[:5]
hash_value = hashlib.sha256(node.attributes["ids"][0].encode()).hexdigest()[:5]
image_node = save_matplotlib_figure(
app, figure, f"need_bar_{hash_value}", fromdocname
)
Expand Down
13 changes: 6 additions & 7 deletions sphinx_needs/directives/needextract.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from sphinx_needs.api.exceptions import NeedsInvalidFilter
from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import SphinxNeedsData
from sphinx_needs.data import NeedsExtractType, SphinxNeedsData
from sphinx_needs.directives.utils import (
no_needs_found_paragraph,
used_filter_paragraph,
Expand Down Expand Up @@ -50,9 +50,7 @@ def run(self) -> Sequence[nodes.Node]:

filter_arg = self.arguments[0] if self.arguments else None

# Add the need and all needed information
data = SphinxNeedsData(env).get_or_create_extracts()
data[targetid] = {
attributes: NeedsExtractType = {
"docname": env.docname,
"lineno": self.lineno,
"target_id": targetid,
Expand All @@ -62,10 +60,12 @@ def run(self) -> Sequence[nodes.Node]:
"filter_arg": filter_arg,
**self.collect_filter_attributes(),
}
node = Needextract("", **attributes)
self.set_source_info(node)

add_doc(env, env.docname, "needextract")

return [targetnode, Needextract("")]
return [targetnode, node]


def process_needextract(
Expand All @@ -85,8 +85,7 @@ def process_needextract(
remove_node_from_tree(node)
continue

id = node.attributes["ids"][0]
current_needextract = SphinxNeedsData(env).get_or_create_extracts()[id]
current_needextract: NeedsExtractType = node.attributes
all_needs = SphinxNeedsData(env).get_or_create_needs()
content: list[nodes.Element] = []

Expand Down
13 changes: 6 additions & 7 deletions sphinx_needs/directives/needfilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from sphinx.errors import NoUri

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import SphinxNeedsData
from sphinx_needs.data import SphinxNeedsData, _NeedsFilterType
from sphinx_needs.diagrams_common import create_legend
from sphinx_needs.directives.utils import no_needs_found_paragraph
from sphinx_needs.filter_common import FilterBase, process_filters
Expand Down Expand Up @@ -55,9 +55,7 @@ def run(self) -> Sequence[nodes.Node]:
)
targetnode = nodes.target("", "", ids=[targetid])

# Add the need and all needed information
data = SphinxNeedsData(env)._get_or_create_filters()
data[targetid] = {
attributes: _NeedsFilterType = {
"docname": env.docname,
"lineno": self.lineno,
"target_id": targetid,
Expand All @@ -68,10 +66,12 @@ def run(self) -> Sequence[nodes.Node]:
"layout": self.options.get("layout", "list"),
**self.collect_filter_attributes(),
}
node = Needfilter("", **attributes)
self.set_source_info(node)

add_doc(env, env.docname)

return [targetnode, Needfilter("")]
return [targetnode, node]


def process_needfilters(
Expand All @@ -94,8 +94,7 @@ def process_needfilters(
remove_node_from_tree(node)
continue

id = node.attributes["ids"][0]
current_needfilter = SphinxNeedsData(env)._get_or_create_filters()[id]
current_needfilter: _NeedsFilterType = node.attributes

content: nodes.Element | list[nodes.Element]
if current_needfilter["layout"] == "list":
Expand Down
11 changes: 5 additions & 6 deletions sphinx_needs/directives/needflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ def run(self) -> Sequence[nodes.Node]:
if config_name and config_name in needs_config.flow_configs:
configs.append(needs_config.flow_configs[config_name])

# Add the need and all needed information
data = SphinxNeedsData(env).get_or_create_flows()
data[targetid] = {
attributes: NeedsFlowType = {
"docname": env.docname,
"lineno": self.lineno,
"target_id": targetid,
Expand All @@ -116,10 +114,12 @@ def run(self) -> Sequence[nodes.Node]:
"caption": self.arguments[0] if self.arguments else None,
**self.collect_filter_attributes(),
}
node = Needflow("", **attributes)
self.set_source_info(node)

add_doc(env, env.docname)

return [targetnode, Needflow("")]
return [targetnode, node]


def make_entity_name(name: str) -> str:
Expand Down Expand Up @@ -372,8 +372,7 @@ def process_needflow(
remove_node_from_tree(node)
continue

id = node.attributes["ids"][0]
current_needflow = env_data.get_or_create_flows()[id]
current_needflow: NeedsFlowType = node.attributes

option_link_types = [link.upper() for link in current_needflow["link_types"]]
for lt in option_link_types:
Expand Down
14 changes: 6 additions & 8 deletions sphinx_needs/directives/needgantt.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import SphinxNeedsData
from sphinx_needs.data import NeedsGanttType, SphinxNeedsData
from sphinx_needs.diagrams_common import (
DiagramBase,
add_config,
Expand Down Expand Up @@ -104,8 +104,7 @@ def run(self) -> Sequence[nodes.Node]:
"completion_option", needs_config.completion_option
)

# Add the needgantt and all needed information
SphinxNeedsData(env).get_or_create_gantts()[targetid] = {
attributes: NeedsGanttType = {
"docname": env.docname,
"lineno": self.lineno,
"target_id": targetid,
Expand All @@ -122,11 +121,11 @@ def run(self) -> Sequence[nodes.Node]:
**self.collect_diagram_attributes(),
}

add_doc(env, env.docname)

gantt_node = Needgantt("")
gantt_node = Needgantt("", **attributes)
self.set_source_info(gantt_node)

add_doc(env, env.docname)

return [targetnode, gantt_node]

def get_link_type_option(self, name: str, default: str = "") -> list[str]:
Expand Down Expand Up @@ -170,8 +169,7 @@ def process_needgantt(
remove_node_from_tree(node)
continue

id = node.attributes["ids"][0]
current_needgantt = SphinxNeedsData(env).get_or_create_gantts()[id]
current_needgantt: NeedsGanttType = node.attributes
all_needs_dict = SphinxNeedsData(env).get_or_create_needs()

content = []
Expand Down
12 changes: 6 additions & 6 deletions sphinx_needs/directives/needlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from sphinx.application import Sphinx

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import SphinxNeedsData
from sphinx_needs.data import NeedsListType, SphinxNeedsData
from sphinx_needs.directives.utils import (
no_needs_found_paragraph,
used_filter_paragraph,
Expand Down Expand Up @@ -46,8 +46,7 @@ def run(self) -> Sequence[nodes.Node]:
)
targetnode = nodes.target("", "", ids=[targetid])

# Add the need and all needed information
SphinxNeedsData(env).get_or_create_lists()[targetid] = {
attributes: NeedsListType = {
"docname": env.docname,
"lineno": self.lineno,
"target_id": targetid,
Expand All @@ -56,10 +55,12 @@ def run(self) -> Sequence[nodes.Node]:
"show_filters": "show_filters" in self.options,
**self.collect_filter_attributes(),
}
list_node = Needlist("", **attributes)
self.set_source_info(list_node)

add_doc(env, env.docname)

return [targetnode, Needlist("")]
return [targetnode, list_node]


def process_needlist(
Expand All @@ -82,8 +83,7 @@ def process_needlist(
remove_node_from_tree(node)
continue

id = node.attributes["ids"][0]
current_needfilter = SphinxNeedsData(env).get_or_create_lists()[id]
current_needfilter: NeedsListType = node.attributes
content: list[nodes.Node] = []
all_needs = list(SphinxNeedsData(env).get_or_create_needs().values())
found_needs = process_filters(app, all_needs, current_needfilter)
Expand Down
Loading

0 comments on commit 0e210b8

Please sign in to comment.