Source code for simvx.editor.error_recovery

"""Error handling for scene instantiation and hot reload."""

import logging
import traceback

from simvx.core import Node
from simvx.core.descriptors import Signal

log = logging.getLogger(__name__)


[docs] class ErrorRecovery: """Manages error state for nodes that fail during instantiation or reload. When a class __init__ raises, the node is marked with _script_error = True. The editor shows a red indicator and the traceback in the output panel. When the file is fixed and hot-reloaded, the node is re-instantiated. """ def __init__(self): self.error_occurred = Signal() # emits (node, traceback_str) self.error_cleared = Signal() # emits (node,) self._errored_nodes: dict[str, tuple[Node, str]] = {} # node_path -> (node, traceback)
[docs] def mark_errored(self, node: Node, tb: str): """Mark a node as errored with traceback info.""" node._script_error = True path = _node_path(node) self._errored_nodes[path] = (node, tb) self.error_occurred.emit(node, tb) log.error("Node %s errored:\n%s", node.name, tb)
[docs] def clear_error(self, node: Node): """Clear error state on a node (after successful reload).""" node._script_error = False path = _node_path(node) self._errored_nodes.pop(path, None) self.error_cleared.emit(node)
[docs] @property def errored_nodes(self) -> list[tuple[Node, str]]: """All errored nodes with their tracebacks.""" return list(self._errored_nodes.values())
[docs] def try_reinstantiate(self, node: Node, cls: type) -> Node | None: """Try to re-instantiate an errored node with a (potentially fixed) class. Returns the new node on success, or None if the class still raises. """ try: new_node = cls() self.clear_error(node) return new_node except Exception: tb = traceback.format_exc() self.mark_errored(node, tb) return None
def _node_path(node: Node) -> str: """Get a stable path string for a node.""" parts = [] n = node while n: parts.append(n.name) n = n.parent return "/".join(reversed(parts))