Skip to content

Commit 4b9a6ad

Browse files
BloggerBustjayanth-kumar-morem
authored andcommitted
fix(runtime): fix return handling for reactive atoms + forward runtime errors to frontend
This commit fixes a bug introduced in `_build_atom_function` that caused value producing component calls like `n = slider(...)` to return `None`. Previously, `ast.Call` nodes were wrapped in an `ast.Expr`, which did not yield a value. This has been corrected by returning an `ast.Return(call_expr)` directly, restoring expected behavior. Additionally, runtime errors (e.g. divide-by-zero) are now forwarded to the frontend during reruns. The `ScriptRunner.rerun` method checks for registered errors and sends them via an `errors:result` message, making error handling reactive and visible to the user.
1 parent 0df19dc commit 4b9a6ad

File tree

2 files changed

+23
-10
lines changed

2 files changed

+23
-10
lines changed

preswald/engine/runner.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,15 @@ async def rerun(self, new_widget_states: dict[str, Any] | None = None):
213213
components = self._service.get_rendered_components()
214214
logger.info(f"[ScriptRunner] Rendered {len(components)} components (rerun)")
215215

216-
if components:
217-
await self.send_message({"type": "components", "components": components})
216+
errors = self._service.get_errors(filename=self.script_path)
217+
message_type = "errors:result" if len(errors) else "components"
218+
219+
if len(components) or len(errors):
220+
await self.send_message({
221+
"type": message_type,
222+
"errors": errors or [],
223+
"components": components or []
224+
})
218225
if logger.isEnabledFor(logging.DEBUG):
219226
logger.debug(f"[ScriptRunner] Sent components to frontend {components=}")
220227
else:

preswald/engine/transformers/reactive_runtime.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,13 +2478,26 @@ def _build_atom_function(
24782478
# Create function parameters: (param0, param1, ...)
24792479
args_ast = self._make_param_args(callsite_deps)
24802480

2481+
callsite_metadata = self._build_callsite_metadata(callsite_node, self.filename)
2482+
decorator = self._create_workflow_atom_decorator(
2483+
atom_name,
2484+
callsite_deps,
2485+
callsite_metadata=callsite_metadata
2486+
)
2487+
24812488
# Normalize call_expr into a body list
24822489
if isinstance(call_expr, list):
24832490
body = call_expr
24842491
elif isinstance(call_expr, ast.Assign) or isinstance(call_expr, ast.Expr):
24852492
body = [call_expr]
24862493
elif isinstance(call_expr, ast.Call):
2487-
body = [ast.Expr(value=call_expr)]
2494+
return_stmt = ast.Return(value=call_expr)
2495+
return ast.FunctionDef(
2496+
name=atom_name,
2497+
args=args_ast,
2498+
body=[return_stmt],
2499+
decorator_list=[decorator],
2500+
)
24882501
else:
24892502
self._safe_register_error(
24902503
node=call_expr,
@@ -2494,13 +2507,6 @@ def _build_atom_function(
24942507
)
24952508
return None
24962509

2497-
callsite_metadata = self._build_callsite_metadata(callsite_node, self.filename)
2498-
decorator = self._create_workflow_atom_decorator(
2499-
atom_name,
2500-
callsite_deps,
2501-
callsite_metadata=callsite_metadata
2502-
)
2503-
25042510
# Append appropriate return statement
25052511
if isinstance(return_target, str):
25062512
body.append(ast.Return(value=ast.Name(id=return_target, ctx=ast.Load())))

0 commit comments

Comments
 (0)