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
|
from ..debug import dump_node_execution
|
||||||
return dump_node_execution(self, socket_name, output_val=None, duration_s=0.0)
|
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)
|
cache = getattr(self, "_current_cache", None)
|
||||||
visited = getattr(self, "_current_visited", None)
|
visited = getattr(self, "_current_visited", None)
|
||||||
inputs = getattr(self, "inputs", None)
|
inputs = getattr(self, "inputs", None)
|
||||||
if inputs is None:
|
if inputs is None:
|
||||||
return None
|
return resolve_input(None, cache=cache, visited=visited, fieldname=fieldname, node=self)
|
||||||
return resolve_input(inputs.get(fieldname), cache=cache, visited=visited)
|
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 = ""):
|
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)
|
bl_idname = NATIVE_SOCKET_MAP.get(bl_idname, bl_idname)
|
||||||
|
|
@ -175,12 +175,12 @@ class SliceNode(Node, AutoBlIdName):
|
||||||
}
|
}
|
||||||
self._update_multi_groups()
|
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)
|
cache = getattr(self, "_current_cache", None)
|
||||||
visited = getattr(self, "_current_visited", None)
|
visited = getattr(self, "_current_visited", None)
|
||||||
# Search by name or identifier prefix for multi-groups
|
# 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_")]
|
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):
|
def _update_multi_groups(self):
|
||||||
if not self.get('multi_groups'): return
|
if not self.get('multi_groups'): return
|
||||||
|
|
@ -582,14 +582,80 @@ def _follow_reroute(current: NodeSocket) -> NodeSocket:
|
||||||
|
|
||||||
return current
|
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(
|
def resolve_input(
|
||||||
socket: SliceNodeSocket | None,
|
socket: SliceNodeSocket | None,
|
||||||
*,
|
*,
|
||||||
cache: _EvalCache | None = None,
|
cache: _EvalCache | None = None,
|
||||||
visited: _VisitedSet | None = None,
|
visited: _VisitedSet | None = None,
|
||||||
|
fieldname: str | None = None,
|
||||||
|
node: Any = None,
|
||||||
):
|
):
|
||||||
if socket is 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
|
assert socket.node
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,40 @@ class TestNodeDebugSystem(unittest.TestCase):
|
||||||
dump = node.dump_inputs("Val")
|
dump = node.dump_inputs("Val")
|
||||||
self.assertEqual(dump["inputs"]["Val"]["value_summary"], 42.0)
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue