A code-declared node's shim names only its triggering ports, so a non-triggering input with no value yet reaches the function as its own default instead of failing the call

This commit is contained in:
2026-11-06 14:35:12 +01:00
parent 40e60b422b
commit 5eec267a7e
2 changed files with 27 additions and 1 deletions
+5 -1
View File
@@ -877,12 +877,16 @@ def _shim(spec: NodeSpec) -> str:
The import is aliased because ``process``'s parameters are the node's port
names, and a port may be named after the very function it feeds — which
would otherwise shadow the import inside the body.
Only the triggering ports are named. The engine leaves out an input that
has no value yet, which only a port that does not trigger can lack, so
those travel in ``**settings`` and the function's own default applies.
"""
_refuse_main(spec)
fn = spec.fn
where = inspect.getsourcefile(fn) or fn.__module__
repo = import_root(fn)
ports = [port.port for port in spec.requires]
ports = [port.port for port in spec.requires if port.trigger]
signature = ", ".join(ports + ["**settings"])
arguments = ", ".join([f"{port}={port}" for port in ports] + ["**settings"])
call = f"_impl({arguments})"
+22
View File
@@ -240,6 +240,28 @@ def test_a_port_named_like_its_function_still_calls_the_function():
assert namespace["process"](scale=2.0) == {"scaled": 4.0}
@node(
requires=["value", Port("factor", "float", trigger=False)],
provides=Port("scaled", "float"),
)
def scale_by(value, factor=3.0):
return value * factor
def test_a_port_that_does_not_trigger_may_be_missing_from_the_call():
"""The engine leaves out an input with no value yet, so the default applies."""
flow = Flow(
"optional",
nodes=[scale_by],
inputs=[Port("value", "float", initial=1.0), Port("factor", "float")],
)
namespace: dict = {}
exec(compile(flow.shims()["scale_by"], "<shim>", "exec"), namespace)
assert namespace["process"](value=2.0) == {"scaled": 6.0}
assert namespace["process"](value=2.0, factor=0.5) == {"scaled": 1.0}
def reads_settings(settings):
return settings