better warnings
This commit is contained in:
parent
973e38fe53
commit
38acdafa55
2 changed files with 105 additions and 6 deletions
|
|
@ -126,13 +126,13 @@ class SliceNode(Node, AutoBlIdName):
|
|||
from ..debug import dump_node_execution
|
||||
return dump_node_execution(self, socket_name, output_val=None, duration_s=0.0)
|
||||
|
||||
def resolve(self, fieldname) -> Any:
|
||||
def resolve(self, fieldname: str) -> Any:
|
||||
cache = getattr(self, "_current_cache", None)
|
||||
visited = getattr(self, "_current_visited", None)
|
||||
inputs = getattr(self, "inputs", None)
|
||||
if inputs is None:
|
||||
return None
|
||||
return resolve_input(inputs.get(fieldname), cache=cache, visited=visited)
|
||||
return resolve_input(None, cache=cache, visited=visited, fieldname=fieldname, node=self)
|
||||
return resolve_input(inputs.get(fieldname), cache=cache, visited=visited, fieldname=fieldname, node=self)
|
||||
|
||||
def add_output(self, bl_idname: str, name: str = "", identifier: str = "", hide: bool = False, display_shape: str = "", description: str = ""):
|
||||
bl_idname = NATIVE_SOCKET_MAP.get(bl_idname, bl_idname)
|
||||
|
|
@ -175,12 +175,12 @@ class SliceNode(Node, AutoBlIdName):
|
|||
}
|
||||
self._update_multi_groups()
|
||||
|
||||
def resolve_multi_input(self, fieldname) -> Any:
|
||||
def resolve_multi_input(self, fieldname: str) -> Any:
|
||||
cache = getattr(self, "_current_cache", None)
|
||||
visited = getattr(self, "_current_visited", None)
|
||||
# Search by name or identifier prefix for multi-groups
|
||||
inputs = [i for i in list(self.inputs) if i.name == fieldname or i.identifier.startswith(f"{fieldname}_ms_in_")]
|
||||
return [resolve_input(r, cache=cache, visited=visited) for r in inputs]
|
||||
return [resolve_input(r, cache=cache, visited=visited, fieldname=fieldname, node=self) for r in inputs]
|
||||
|
||||
def _update_multi_groups(self):
|
||||
if not self.get('multi_groups'): return
|
||||
|
|
@ -582,14 +582,80 @@ def _follow_reroute(current: NodeSocket) -> NodeSocket:
|
|||
|
||||
return current
|
||||
|
||||
def _format_node_description(node: Any) -> str:
|
||||
if node is None:
|
||||
return ""
|
||||
name = getattr(node, "name", "")
|
||||
bl_label = getattr(node, "bl_label", "")
|
||||
bl_idname = getattr(node, "bl_idname", "") or type(node).__name__
|
||||
|
||||
label = bl_label or bl_idname
|
||||
if name and label and name != label:
|
||||
return f"'{name}' ({label})"
|
||||
elif name:
|
||||
return f"'{name}'"
|
||||
elif label:
|
||||
return f"'{label}'"
|
||||
return str(node)
|
||||
|
||||
|
||||
def _extract_caller_context() -> tuple[Any, str | None]:
|
||||
try:
|
||||
import sys
|
||||
for depth in range(2, 6):
|
||||
try:
|
||||
frame = sys._getframe(depth)
|
||||
except ValueError:
|
||||
break
|
||||
caller_self = frame.f_locals.get("self")
|
||||
caller_node = None
|
||||
if caller_self is not None and (
|
||||
isinstance(caller_self, Node) or
|
||||
hasattr(caller_self, "bl_idname") or
|
||||
hasattr(caller_self, "inputs")
|
||||
):
|
||||
caller_node = caller_self
|
||||
|
||||
caller_fieldname = (
|
||||
frame.f_locals.get("fieldname") or
|
||||
frame.f_locals.get("socket_name") or
|
||||
frame.f_locals.get("name")
|
||||
)
|
||||
if not isinstance(caller_fieldname, str):
|
||||
caller_fieldname = None
|
||||
|
||||
if caller_node is not None or caller_fieldname is not None:
|
||||
return caller_node, caller_fieldname
|
||||
except Exception:
|
||||
pass
|
||||
return None, None
|
||||
|
||||
|
||||
def resolve_input(
|
||||
socket: SliceNodeSocket | None,
|
||||
*,
|
||||
cache: _EvalCache | None = None,
|
||||
visited: _VisitedSet | None = None,
|
||||
fieldname: str | None = None,
|
||||
node: Any = None,
|
||||
):
|
||||
if socket is None:
|
||||
raise Exception(f"The queried socket is non-existant")
|
||||
if node is None or fieldname is None:
|
||||
caller_node, caller_fieldname = _extract_caller_context()
|
||||
if node is None:
|
||||
node = caller_node
|
||||
if fieldname is None:
|
||||
fieldname = caller_fieldname
|
||||
|
||||
node_str = _format_node_description(node)
|
||||
if fieldname and node_str:
|
||||
raise NodeException(f"The queried socket '{fieldname}' on node {node_str} is non-existent")
|
||||
elif fieldname:
|
||||
raise NodeException(f"The queried socket '{fieldname}' is non-existent")
|
||||
elif node_str:
|
||||
raise NodeException(f"The queried socket on node {node_str} is non-existent")
|
||||
else:
|
||||
raise NodeException("The queried socket is non-existent")
|
||||
|
||||
assert socket.node
|
||||
|
||||
|
|
|
|||
|
|
@ -321,7 +321,40 @@ class TestNodeDebugSystem(unittest.TestCase):
|
|||
dump = node.dump_inputs("Val")
|
||||
self.assertEqual(dump["inputs"]["Val"]["value_summary"], 42.0)
|
||||
|
||||
def test_non_existent_socket_error_message_with_resolve(self):
|
||||
from NodeSlicer.infra.blender.blender_slice_nodes_generic import NodeException
|
||||
|
||||
class TestNode(SliceNode):
|
||||
bl_idname = "SLICENODE_Test"
|
||||
bl_label = "Test Node"
|
||||
|
||||
def __init__(self):
|
||||
self.name = "My Test Node"
|
||||
self.inputs = DummySocketCollection([
|
||||
DummyNodeSocket("Valid", "Valid", "NodeSocketFloat", value=1.0)
|
||||
], node=self)
|
||||
|
||||
node = TestNode()
|
||||
with self.assertRaises(NodeException) as ctx:
|
||||
node.resolve("NonExistentSocket")
|
||||
|
||||
err_msg = str(ctx.exception)
|
||||
self.assertIn("NonExistentSocket", err_msg)
|
||||
self.assertIn("My Test Node", err_msg)
|
||||
self.assertIn("Test Node", err_msg)
|
||||
self.assertIn("non-existent", err_msg)
|
||||
|
||||
def test_non_existent_socket_error_message_isolated(self):
|
||||
from NodeSlicer.infra.blender.blender_slice_nodes_generic import NodeException, resolve_input
|
||||
|
||||
with self.assertRaises(NodeException) as ctx:
|
||||
resolve_input(None)
|
||||
|
||||
err_msg = str(ctx.exception)
|
||||
self.assertIn("non-existent", err_msg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue