Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/ewoksdraw/graph_to_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,32 @@
from .svg.svg_canvas import SvgCanvas
from .svg.svg_task import SvgTask
from .svg.svg_task_group import SvgTaskGroup
from .utils import get_edge_sources_and_targets


def build_svg_task_group(graph: TaskGraph) -> SvgTaskGroup:
"""Build an SVG task group from an Ewoks task graph."""
source_outputs_per_node, target_inputs_per_node = get_edge_sources_and_targets(
graph
)

svg_tasks = {}
for node_id, node_attrs in graph.graph.nodes.items():
signature = node_signature(node_id, node_attrs)

# Use dict instead of set to remove duplicate while keeping order
inputs = dict.fromkeys(node_input.name for node_input in signature.inputs)
# Add eventual missing target inputs
inputs.update(dict.fromkeys(target_inputs_per_node[node_id]))

outputs = dict.fromkeys(node_output.name for node_output in signature.outputs)
# Add eventual missing source outputs
outputs.update(dict.fromkeys(source_outputs_per_node[node_id]))

svg_tasks[node_id] = SvgTask(
task_name=node_id,
input_names=[node_input.name for node_input in signature.inputs],
output_names=[node_output.name for node_output in signature.outputs],
input_names=list(inputs.keys()),
output_names=list(outputs.keys()),
import_error=bool(signature.import_error),
)
return SvgTaskGroup(
Expand Down
48 changes: 15 additions & 33 deletions src/ewoksdraw/layout/elk_converter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import warnings
from typing import Any

from ..utils import get_valid_data_mappings

try:
from typing import NotRequired
except ImportError:
Expand Down Expand Up @@ -152,38 +153,19 @@ def convert_ewoks_to_elk_graph(
used_ids.add(root_id)

edges: list[ElkEdgeBeforeLayout] = []
for source, target, link_attrs in ewoks_graph.graph.edges(data=True):
if link_attrs.get("map_all_data", False):
warnings.warn(
f"Ewoks link {source!r} -> {target!r} uses 'map_all_data', which "
"is not yet supported.",
UserWarning,
stacklevel=2,
)

for mapping in link_attrs.get("data_mapping", []):
source_output = mapping.get("source_output")
if source_output is None:
warnings.warn(
f"Data mapping on Ewoks link {source!r} -> {target!r} has no "
"'source_output', which is not yet supported.",
UserWarning,
stacklevel=2,
)
continue

edge_id = _available_elk_id(
f"edge_{len(edges)}_{source}_{target}", used_ids
)

edges.append(
{
"id": edge_id,
"sources": [f"{source}.output.{source_output}"],
"targets": [f"{target}.input.{mapping['target_input']}"],
}
)
used_ids.add(edge_id)
for mapping in get_valid_data_mappings(ewoks_graph):
edge_id = _available_elk_id(
f"edge_{len(edges)}_{mapping.source}_{mapping.target}", used_ids
)

edges.append(
{
"id": edge_id,
"sources": [f"{mapping.source}.output.{mapping.source_output}"],
"targets": [f"{mapping.target}.input.{mapping.target_input}"],
}
)
used_ids.add(edge_id)

return {
"id": root_id,
Expand Down
8 changes: 8 additions & 0 deletions src/ewoksdraw/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import NamedTuple


class DataMapping(NamedTuple):
source: str
target: str
source_output: str
target_input: str
53 changes: 53 additions & 0 deletions src/ewoksdraw/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import warnings
from collections import defaultdict

from ewokscore.graph import TaskGraph

from .models import DataMapping


def get_valid_data_mappings(ewoks_graph: TaskGraph) -> list[DataMapping]:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New util to go through data mappings in the new get_edge_sources_and_targets function

data_mappings: list[DataMapping] = []
for source, target, link_attrs in ewoks_graph.graph.edges(data=True):
if link_attrs.get("map_all_data", False):
warnings.warn(
f"Ewoks link {source!r} -> {target!r} uses 'map_all_data', which "
"is not yet supported.",
UserWarning,
stacklevel=2,
)

for mapping in link_attrs.get("data_mapping", []):
source_output = mapping.get("source_output")
if source_output is None:
warnings.warn(
f"Data mapping on Ewoks link {source!r} -> {target!r} has no "
"'source_output', which is not yet supported.",
UserWarning,
stacklevel=2,
)
continue

data_mappings.append(
DataMapping(
source=source,
target=target,
source_output=source_output,
target_input=mapping["target_input"],
)
)

return data_mappings


def get_edge_sources_and_targets(
graph: TaskGraph,
) -> tuple[dict[str, list[str]], dict[str, list[str]]]:
data_mappings = get_valid_data_mappings(graph)
sources: dict[str, list[str]] = defaultdict(list[str])
targets: dict[str, list[str]] = defaultdict(list[str])
for mapping in data_mappings:
sources[mapping.source].append(mapping.source_output)
targets[mapping.target].append(mapping.target_input)

return sources, targets
Comment on lines +43 to +53

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to avoid the double warning.
You can instead pass the data_mapping as a parameter and make the helper function a pure transformation.

def get_edge_sources_and_targets(
    data_mappings: list[DataMapping],
) -> tuple[dict[str, list[str]], dict[str, list[str]]]:

Let build_svg_task_group() / convert_ewoks_to_elk_graph() receive the mappings
And finnaly called in once in graph_to_svg():

def graph_to_svg(graph: TaskGraph, output_path: str | Path) -> None:
    data_mappings = get_valid_data_mappings(graph)

    task_group = build_svg_task_group(
        graph,
        data_mappings,
    )

    elk_graph_before_layout = convert_ewoks_to_elk_graph(
        graph,
        task_group.extract_task_sizes(),
        task_group.extract_input_positions(),
        task_group.extract_output_positions(),
        data_mappings,
    )

Having the warning twice might be better :). You're the judge on that one.

@loichuder loichuder Sep 28, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean this would be an alternative to b3d0dec ?

Or that there is still a duplication of warnings even with b3d0dec?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right I got lost in PR. It's fine with b3d0dec

Loading