Let a port be named after the function it feeds
The generated node body imported the function under its own name and then gave `process` the ports as parameters, so a port named like its function shadowed the import and the call became a value calling itself — `TypeError: 'str' object is not callable`, with the downstream node's missing arguments as the knock-on. The import is aliased now. Only the two names the body needs itself, `settings` and `_impl`, are refused at sync. Every shim's text moves once, so the next sync reports every code-defined node updated and each cached node misses a single time. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TXQv6KNyyvY7Z1etYTUUAd
This commit is contained in:
@@ -187,15 +187,15 @@ def test_shim_imports_rather_than_copies():
|
||||
shims = a_flow().shims()
|
||||
|
||||
assert shims["prepare"].startswith(MARKER)
|
||||
assert "from tests.sdk.test_build import prepare" in shims["prepare"]
|
||||
assert "from tests.sdk.test_build import prepare as _impl" in shims["prepare"]
|
||||
assert "def process(**settings):" in shims["prepare"]
|
||||
assert "return prepare(**settings)" in shims["prepare"]
|
||||
assert "return _impl(**settings)" in shims["prepare"]
|
||||
|
||||
|
||||
def test_shim_of_a_generator_delegates_and_keeps_its_return_value():
|
||||
"""A bare `yield from` streams but drops what the generator returns."""
|
||||
assert (
|
||||
"return (yield from fit(dataset=dataset, lr=lr, **settings))"
|
||||
"return (yield from _impl(dataset=dataset, lr=lr, **settings))"
|
||||
in a_flow().shims()["fit"]
|
||||
)
|
||||
|
||||
@@ -221,7 +221,31 @@ def test_a_generator_shim_publishes_both_the_stream_and_the_result():
|
||||
|
||||
|
||||
def test_shim_of_a_single_port_wraps_the_bare_return():
|
||||
assert "return {'score': evaluate(weights=weights" in a_flow().shims()["evaluate"]
|
||||
assert "return {'score': _impl(weights=weights" in a_flow().shims()["evaluate"]
|
||||
|
||||
|
||||
@node(requires=["scale"], provides=Port("scaled", "float"))
|
||||
def scale(scale):
|
||||
return scale * 2.0
|
||||
|
||||
|
||||
def test_a_port_named_like_its_function_still_calls_the_function():
|
||||
"""The body imports under an alias, so the port cannot shadow the function."""
|
||||
flow = Flow("collide", nodes=[scale], inputs=[Port("scale", "float", initial=1.0)])
|
||||
namespace: dict = {}
|
||||
exec(compile(flow.shims()["scale"], "<shim>", "exec"), namespace)
|
||||
|
||||
assert namespace["process"](scale=2.0) == {"scaled": 4.0}
|
||||
|
||||
|
||||
def reads_settings(settings):
|
||||
return settings
|
||||
|
||||
|
||||
def test_a_port_the_generated_body_reserves_is_refused():
|
||||
refused = node(requires=["settings"], provides=Port("out", "float"))(reads_settings)
|
||||
with pytest.raises(SyncError, match="keeps for itself"):
|
||||
Flow("reserved", nodes=[refused], inputs=[Port("settings", "float")])
|
||||
|
||||
|
||||
def test_every_shim_compiles_and_defines_process():
|
||||
|
||||
Reference in New Issue
Block a user