Skip to content
Open
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
35 changes: 18 additions & 17 deletions src/node_graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,23 +716,24 @@ def links_from_dict(self, links: list) -> None:
)
parent._append_dynamic_child(part, {})
parent = parent[part]
if not isinstance(parent, TaskSocketNamespace):
raise ValueError(
f"Cannot create socket '{socket_path}' under leaf "
f"{parent._full_name_with_task}."
)
if not parent._metadata.dynamic:
raise ValueError(
f"Missing socket '{socket_path}' in {task.name}.inputs and "
"parent namespace is not dynamic."
)
if (
isinstance(source, TaskSocketNamespace)
or getattr(source, "_scoped_name", None) == OUTPUT_SOCKET_NAME
):
parent._append_dynamic_child(parts[-1], {})
else:
parent._append_dynamic_child(parts[-1], None)
if parts[-1] not in parent:
if not isinstance(parent, TaskSocketNamespace):
raise ValueError(
f"Cannot create socket '{socket_path}' under leaf "
f"{parent._full_name_with_task}."
)
if not parent._metadata.dynamic:
raise ValueError(
f"Missing socket '{socket_path}' in {task.name}.inputs and "
"parent namespace is not dynamic."
)
if (
isinstance(source, TaskSocketNamespace)
or getattr(source, "_scoped_name", None) == OUTPUT_SOCKET_NAME
):
parent._append_dynamic_child(parts[-1], {})
else:
parent._append_dynamic_child(parts[-1], None)
target = parent[parts[-1]]
self.add_link(source, target, allow_skip_linked=True)

Expand Down
52 changes: 51 additions & 1 deletion tests/test_graph.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from node_graph import Graph, task, namespace
from node_graph import Graph, task, namespace, dynamic
from node_graph.config import INPUT_SOCKET_NAME, OUTPUT_SOCKET_NAME
import pytest
from typing import Any
Expand Down Expand Up @@ -188,6 +188,56 @@ def test(a, b=1, nested: namespace(d=Any, f=namespace(g=Any, h=Any)) = {}):
assert ng1.tasks.test1.inputs._value == ng.tasks.test1.inputs._value


def test_load_graph_mixed_dynamic_static_namespace():
@task(
outputs=namespace(
set1=namespace(a=Any, b=Any),
set2=namespace(a=Any, b=Any),
)
)
def generate_sets():
return {
"set1": {"a": 1, "b": 5},
"set2": {"a": -3, "b": 2},
}

@task(
outputs=dynamic(namespace(sum=Any, product=Any)),
)
def test(nested: dynamic(namespace(a=Any, b=Any)) = {}):
return {
k: {
"sum": v["a"] + v["b"],
"product": v["a"] * v["b"],
}
for k, v in nested.items()
}

ng = Graph()
test1 = ng.add_task(generate_sets, "test1")
test2 = ng.add_task(test, "test2")
test2.set_inputs(
{
"nested": {
"set1": {
"a": test1.outputs.set1.a,
"b": test1.outputs.set1.b,
},
"set2": {
"a": test1.outputs.set2.a,
"b": test1.outputs.set2.b,
},
}
}
)
ngdata = ng.to_dict()
# load graph
ng1 = Graph.from_dict(ngdata)
assert ng1.tasks.test2.outputs._metadata.extras["dynamic"]
assert "sum" in ng1.tasks.test2.outputs._metadata.extras["item"]["fields"]
assert ng1.tasks.test2.inputs._value == ng.tasks.test2.inputs._value


def test_expose_inputs(test_ng):
"""Test generation of inputs from tasks"""
ng = test_ng
Expand Down
Loading