Skip to content

Commit 9ca4e23

Browse files
authored
🔧 Centralise sphinx env data access (and add schemas) (#987)
The sphinx-needs data stored on the Sphinx `BuildEnvironment` is currently difficult to interpret and work with, since the dynamic nature of `BuildEnvironment` provides no type safety or static introspection. This commit centralises access to sphinx-needs data, via `sphinx_needs.data.SphinxNeedsData`, which is a thin wrapper around the sphinx `BuildEnvironment`, to define and provide type safe access to the sphinx-need specific data. `TypedDict` are used to type annotate the dictionary keys for the different data types, and thus `sphinx_needs.data` essentially provides a schema for the data that sphinx-needs stores. This is a non-breaking change, since all data can still be accessed via the sphinx `BuildEnvironment`, (although this is now discouraged).
1 parent 1ecb2b7 commit 9ca4e23

32 files changed

+985
-457
lines changed

‎pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ warn_unused_ignores = false
9393
module = [
9494
'sphinx_needs.api.need',
9595
'sphinx_needs.builder',
96+
'sphinx_needs.data',
9697
'sphinx_needs.diagrams_common',
9798
'sphinx_needs.directives.need',
9899
'sphinx_needs.directives.needbar',
@@ -116,6 +117,7 @@ module = [
116117
'sphinx_needs.needs',
117118
'sphinx_needs.needsfile',
118119
'sphinx_needs.roles.need_incoming',
120+
'sphinx_needs.roles.need_outgoing',
119121
'sphinx_needs.roles.need_part',
120122
'sphinx_needs.roles.need_ref',
121123
'sphinx_needs.services.github',

‎sphinx_needs/api/need.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
NeedsTemplateException,
2323
)
2424
from sphinx_needs.config import NeedsSphinxConfig
25+
from sphinx_needs.data import NeedsInfoType, SphinxNeedsData
2526
from sphinx_needs.directives.needuml import Needuml, NeedumlException
2627
from sphinx_needs.filter_common import filter_single_need
2728
from sphinx_needs.logging import get_logger
@@ -271,11 +272,8 @@ def run():
271272
#############################################################################################
272273
# Add need to global need list
273274
#############################################################################################
274-
# be sure, global var is available. If not, create it
275-
if not hasattr(env, "needs_all_needs"):
276-
env.needs_all_needs = {}
277275

278-
if need_id in env.needs_all_needs:
276+
if need_id in SphinxNeedsData(env).get_or_create_needs():
279277
if id:
280278
raise NeedsDuplicatedId(
281279
f"A need with ID {need_id} already exists! "
@@ -307,7 +305,7 @@ def run():
307305
doctype = ".rst"
308306

309307
# Add the need and all needed information
310-
needs_info = {
308+
needs_info: NeedsInfoType = {
311309
"docname": docname,
312310
"doctype": doctype,
313311
"lineno": lineno,
@@ -403,7 +401,7 @@ def run():
403401
content = new_content
404402
needs_info["content"] = new_content
405403

406-
env.needs_all_needs[need_id] = needs_info
404+
SphinxNeedsData(env).get_or_create_needs()[need_id] = needs_info
407405

408406
# Template builds
409407
##############################
@@ -457,7 +455,7 @@ def run():
457455
if isinstance(child, Needuml):
458456
needuml_id = child.rawsource
459457
try:
460-
needuml = env.needs_all_needumls.get(needuml_id)
458+
needuml = SphinxNeedsData(env).get_or_create_umls().get(needuml_id)
461459
key_name = needuml["key"]
462460
if key_name:
463461
# check if key_name already exists in needs_info["arch"]
@@ -507,8 +505,9 @@ def del_need(app: Sphinx, need_id: str) -> None:
507505
:param need_id: Sphinx need id.
508506
"""
509507
env = unwrap(app.env)
510-
if need_id in env.needs_all_needs:
511-
del env.needs_all_needs[need_id]
508+
needs = SphinxNeedsData(env).get_or_create_needs()
509+
if need_id in needs:
510+
del needs[need_id]
512511
else:
513512
logger.warning(f"Given need id {need_id} not exists! [needs]", type="needs")
514513

‎sphinx_needs/builder.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from sphinx.builders import Builder
88

99
from sphinx_needs.config import NeedsSphinxConfig
10+
from sphinx_needs.data import SphinxNeedsData
1011
from sphinx_needs.logging import get_logger
1112
from sphinx_needs.needsfile import NeedsList
1213
from sphinx_needs.utils import unwrap
@@ -25,8 +26,9 @@ def write_doc(self, docname: str, doctree: nodes.document) -> None:
2526

2627
def finish(self) -> None:
2728
env = unwrap(self.env)
28-
needs = env.needs_all_needs.values() # We need a list of needs for later filter checks
29-
filters = env.needs_all_filters
29+
data = SphinxNeedsData(env)
30+
needs = data.get_or_create_needs().values() # We need a list of needs for later filter checks
31+
filters = data.get_or_create_filters()
3032
version = getattr(env.config, "version", "unset")
3133
needs_list = NeedsList(env.config, self.outdir, self.srcdir)
3234
needs_config = NeedsSphinxConfig(env.config)
@@ -107,7 +109,7 @@ def write_doc(self, docname: str, doctree: nodes.document) -> None:
107109

108110
def finish(self) -> None:
109111
env = unwrap(self.env)
110-
needumls = env.needs_all_needumls.values()
112+
needumls = SphinxNeedsData(env).get_or_create_umls().values()
111113

112114
for needuml in needumls:
113115
if needuml["save"]:

0 commit comments

Comments
 (0)