sphinx-needs icon indicating copy to clipboard operation
sphinx-needs copied to clipboard

Request: enable needuml to modify needs

Open AlexanderLanin opened this issue 1 year ago • 2 comments

Abstract

For every element used in needuml/needarch we want to add a link to the need itself to every image it's used in. A generated "used_in_image" option. The current approach is to inject a custom uml-function (like e.g. ref), which will modify the need element when used.

However modifications to the need do not take effect, as they simply happen too late in the workflow.

Approach in Detail:

  • I'm injecting an "uml-function", I'm calling it "element". Approach: #1206
  • In plantuml I'm using it like: participant {{element('demo1_A')}} (I have a workaround for getting all needs into the function via storing the app into a global variable; see also #1207)
  • That "element" uml-function simply modifies the referenced need: need["used_in_image"] = current_document (full code below)

Problem in Detail:

  • uml is processed within process_creator
  • needs become "read only" after process_need_nodes, specifically format_need_nodes See https://github.com/useblocks/sphinx-needs/blob/f3745ffd8ab9d3c3ed079554b746d0d53162fe18/sphinx_needs/needs.py#L291-L292

Possible solution:

  • There is no reason, why format_need_nodes needs to called by process_need_nodes. It could be called later after process_creator. Looks like it was there to avoid redundant findall calls, but it's not redundant (anymore).
  • However, it's not that trivial as format_need_nodes evaluates the "hide" option. Not doing so before needpie etc could change the diagrams.

Not addressed here in this issue:

  • How do get the current document within the uml-function
  • How to add anchor tags to uml-images

Code just for reference:

current_app: sphinx.application.Sphinx | None = None


def get_needs() -> dict[str, dict[str, Any]]:
    assert current_app
    assert current_app.env
    # old way of accessing needs:
    assert current_app.env.needs_all_needs
    assert isinstance(current_app.env.needs_all_needs, dict)
    return current_app.env.needs_all_needs

def uml_element(need: dict | str):
    if isinstance(need, str):
        needs = get_needs()
        need = needs[need]

    # FIXME: can we access current document through app? and potentially current need?
    current_document = need["docname"]

    # Modifying needs has no effect at this point in time !!
    needs[need_id]["used_in_image"] += current_document + ".html;"

    link = sphinx_needs.diagrams_common.calculate_link(
        current_app, need, current_document
    )
    title = need["title"]
    need_id = need["id"]

    return f'"[[{link} {title}]]" as {need_id}'

def setup(app: sphinx.application.Sphinx):
    global current_app  # noqa: PLW0603
    current_app = app

AlexanderLanin avatar Sep 06 '24 08:09 AlexanderLanin

Correction: maybe the change is simple after all while preserving current behavior.

Currently when elements have the :hide: option, they do appear in e.g. needtable and they can be referenced from needuml.

AlexanderLanin avatar Sep 06 '24 10:09 AlexanderLanin

May be also relevant for the S-Core project: https://github.com/eclipse-score/score/issues/658

danwos avatar Mar 14 '25 08:03 danwos