Skip to content

Commit 8d4e063

Browse files
authored
Add union link connection type support (#5806)
* Add union type support * Move code * nit
1 parent 57e8bf6 commit 8d4e063

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

comfy_execution/validation.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
3+
4+
def validate_node_input(
5+
received_type: str, input_type: str, strict: bool = False
6+
) -> bool:
7+
"""
8+
received_type and input_type are both strings of the form "T1,T2,...".
9+
10+
If strict is True, the input_type must contain the received_type.
11+
For example, if received_type is "STRING" and input_type is "STRING,INT",
12+
this will return True. But if received_type is "STRING,INT" and input_type is
13+
"INT", this will return False.
14+
15+
If strict is False, the input_type must have overlap with the received_type.
16+
For example, if received_type is "STRING,BOOLEAN" and input_type is "STRING,INT",
17+
this will return True.
18+
"""
19+
# If the types are exactly the same, we can return immediately
20+
if received_type == input_type:
21+
return True
22+
23+
# Split the type strings into sets for comparison
24+
received_types = set(t.strip() for t in received_type.split(","))
25+
input_types = set(t.strip() for t in input_type.split(","))
26+
27+
if strict:
28+
# In strict mode, all received types must be in the input types
29+
return received_types.issubset(input_types)
30+
else:
31+
# In non-strict mode, there must be at least one type in common
32+
return len(received_types.intersection(input_types)) > 0

execution.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from comfy_execution.graph import get_input_info, ExecutionList, DynamicPrompt, ExecutionBlocker
1717
from comfy_execution.graph_utils import is_link, GraphBuilder
1818
from comfy_execution.caching import HierarchicalCache, LRUCache, CacheKeySetInputSignature, CacheKeySetID
19+
from comfy_execution.validation import validate_node_input
1920
from comfy.cli_args import args
2021

2122
class ExecutionResult(Enum):
@@ -527,7 +528,6 @@ def execute(self, prompt, prompt_id, extra_data={}, execute_outputs=[]):
527528
comfy.model_management.unload_all_models()
528529

529530

530-
531531
def validate_inputs(prompt, item, validated):
532532
unique_id = item
533533
if unique_id in validated:
@@ -589,8 +589,8 @@ def validate_inputs(prompt, item, validated):
589589
r = nodes.NODE_CLASS_MAPPINGS[o_class_type].RETURN_TYPES
590590
received_type = r[val[1]]
591591
received_types[x] = received_type
592-
if 'input_types' not in validate_function_inputs and received_type != type_input:
593-
details = f"{x}, {received_type} != {type_input}"
592+
if 'input_types' not in validate_function_inputs and not validate_node_input(received_type, type_input):
593+
details = f"{x}, received_type({received_type}) mismatch input_type({type_input})"
594594
error = {
595595
"type": "return_type_mismatch",
596596
"message": "Return type mismatch between linked nodes",
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import pytest
2+
from comfy_execution.validation import validate_node_input
3+
4+
5+
def test_exact_match():
6+
"""Test cases where types match exactly"""
7+
assert validate_node_input("STRING", "STRING")
8+
assert validate_node_input("STRING,INT", "STRING,INT")
9+
assert (
10+
validate_node_input("INT,STRING", "STRING,INT")
11+
) # Order shouldn't matter
12+
13+
14+
def test_strict_mode():
15+
"""Test strict mode validation"""
16+
# Should pass - received type is subset of input type
17+
assert validate_node_input("STRING", "STRING,INT", strict=True)
18+
assert validate_node_input("INT", "STRING,INT", strict=True)
19+
assert validate_node_input("STRING,INT", "STRING,INT,BOOLEAN", strict=True)
20+
21+
# Should fail - received type is not subset of input type
22+
assert not validate_node_input("STRING,INT", "STRING", strict=True)
23+
assert not validate_node_input("STRING,BOOLEAN", "STRING", strict=True)
24+
assert not validate_node_input("INT,BOOLEAN", "STRING,INT", strict=True)
25+
26+
27+
def test_non_strict_mode():
28+
"""Test non-strict mode validation (default behavior)"""
29+
# Should pass - types have overlap
30+
assert validate_node_input("STRING,BOOLEAN", "STRING,INT")
31+
assert validate_node_input("STRING,INT", "INT,BOOLEAN")
32+
assert validate_node_input("STRING", "STRING,INT")
33+
34+
# Should fail - no overlap in types
35+
assert not validate_node_input("BOOLEAN", "STRING,INT")
36+
assert not validate_node_input("FLOAT", "STRING,INT")
37+
assert not validate_node_input("FLOAT,BOOLEAN", "STRING,INT")
38+
39+
40+
def test_whitespace_handling():
41+
"""Test that whitespace is handled correctly"""
42+
assert validate_node_input("STRING, INT", "STRING,INT")
43+
assert validate_node_input("STRING,INT", "STRING, INT")
44+
assert validate_node_input(" STRING , INT ", "STRING,INT")
45+
assert validate_node_input("STRING,INT", " STRING , INT ")
46+
47+
48+
def test_empty_strings():
49+
"""Test behavior with empty strings"""
50+
assert validate_node_input("", "")
51+
assert not validate_node_input("STRING", "")
52+
assert not validate_node_input("", "STRING")
53+
54+
55+
def test_single_vs_multiple():
56+
"""Test single type against multiple types"""
57+
assert validate_node_input("STRING", "STRING,INT,BOOLEAN")
58+
assert validate_node_input("STRING,INT,BOOLEAN", "STRING", strict=False)
59+
assert not validate_node_input("STRING,INT,BOOLEAN", "STRING", strict=True)
60+
61+
62+
@pytest.mark.parametrize(
63+
"received,input_type,strict,expected",
64+
[
65+
("STRING", "STRING", False, True),
66+
("STRING,INT", "STRING,INT", False, True),
67+
("STRING", "STRING,INT", True, True),
68+
("STRING,INT", "STRING", True, False),
69+
("BOOLEAN", "STRING,INT", False, False),
70+
("STRING,BOOLEAN", "STRING,INT", False, True),
71+
],
72+
)
73+
def test_parametrized_cases(received, input_type, strict, expected):
74+
"""Parametrized test cases for various scenarios"""
75+
assert validate_node_input(received, input_type, strict) == expected

0 commit comments

Comments
 (0)