Make execution.validate_inputs properly validate required dynamic inputs, renamed dynamic_data to dynamic_paths for clarity

This commit is contained in:
Jedrzej Kosinski 2025-11-18 06:20:09 -08:00
parent 85edfc8e6b
commit ffe77c2959
2 changed files with 16 additions and 15 deletions

View File

@ -941,14 +941,6 @@ class Autogrow(ComfyTypeI):
curr_prefix = f"{curr_prefix}{self.id}." curr_prefix = f"{curr_prefix}{self.id}."
self.template.add_to_dict_live_inputs(d, live_inputs, curr_prefix) self.template.add_to_dict_live_inputs(d, live_inputs, curr_prefix)
def add_dynamic_id_mapping(d: dict[str], inputs: list[Input], curr_prefix: str, self: DynamicInput=None):
dynamic = d.setdefault("dynamic_data", {})
if self is not None:
dynamic[self.id] = f"{curr_prefix}{self.id}"
for i in inputs:
if not isinstance(i, DynamicInput):
dynamic[f"{i.id}"] = f"{curr_prefix}{i.id}"
@comfytype(io_type="COMFY_DYNAMICCOMBO_V3") @comfytype(io_type="COMFY_DYNAMICCOMBO_V3")
class DynamicCombo(ComfyTypeI): class DynamicCombo(ComfyTypeI):
Type = dict[str] Type = dict[str]
@ -1046,9 +1038,17 @@ class MatchType(ComfyTypeIO):
"template": self.template.as_dict(), "template": self.template.as_dict(),
}) })
def add_dynamic_id_mapping(d: dict[str], inputs: list[Input], curr_prefix: str, self: DynamicInput=None):
dynamic = d.setdefault("dynamic_paths", {})
if self is not None:
dynamic[self.id] = f"{curr_prefix}{self.id}"
for i in inputs:
if not isinstance(i, DynamicInput):
dynamic[f"{i.id}"] = f"{curr_prefix}{i.id}"
class V3Data(TypedDict): class V3Data(TypedDict):
hidden_inputs: dict[str] hidden_inputs: dict[str]
dynamic_data: dict[str] dynamic_paths: dict[str]
class HiddenHolder: class HiddenHolder:
def __init__(self, unique_id: str, prompt: Any, def __init__(self, unique_id: str, prompt: Any,
@ -1354,7 +1354,7 @@ def add_to_dict_v3(io: Input | Output, d: dict):
d[io.id] = (io.get_io_type(), io.as_dict()) d[io.id] = (io.get_io_type(), io.as_dict())
def build_nested_inputs(values: dict[str], v3_data: V3Data): def build_nested_inputs(values: dict[str], v3_data: V3Data):
paths = v3_data.get("dynamic_data", None) paths = v3_data.get("dynamic_paths", None)
if paths is None: if paths is None:
return values return values
values = values.copy() values = values.copy()
@ -1624,9 +1624,9 @@ class _ComfyNodeBaseInternal(_ComfyNodeInternal):
input.pop("hidden", None) input.pop("hidden", None)
if return_schema: if return_schema:
v3_data: V3Data = {} v3_data: V3Data = {}
dynamic = input.pop("dynamic_data", None) dynamic = input.pop("dynamic_paths", None)
if dynamic is not None: if dynamic is not None:
v3_data["dynamic_data"] = dynamic v3_data["dynamic_paths"] = dynamic
return input, schema, v3_data return input, schema, v3_data
return input return input

View File

@ -750,18 +750,17 @@ async def validate_inputs(prompt_id, prompt, item, validated):
class_type = prompt[unique_id]['class_type'] class_type = prompt[unique_id]['class_type']
obj_class = nodes.NODE_CLASS_MAPPINGS[class_type] obj_class = nodes.NODE_CLASS_MAPPINGS[class_type]
class_inputs = obj_class.INPUT_TYPES()
valid_inputs = set(class_inputs.get('required',{})).union(set(class_inputs.get('optional',{})))
errors = [] errors = []
valid = True valid = True
validate_function_inputs = [] validate_function_inputs = []
validate_has_kwargs = False validate_has_kwargs = False
if issubclass(obj_class, _ComfyNodeInternal): if issubclass(obj_class, _ComfyNodeInternal):
class_inputs, _, _ = obj_class.INPUT_TYPES(include_hidden=False, return_schema=True, live_inputs=inputs)
validate_function_name = "validate_inputs" validate_function_name = "validate_inputs"
validate_function = first_real_override(obj_class, validate_function_name) validate_function = first_real_override(obj_class, validate_function_name)
else: else:
class_inputs = obj_class.INPUT_TYPES()
validate_function_name = "VALIDATE_INPUTS" validate_function_name = "VALIDATE_INPUTS"
validate_function = getattr(obj_class, validate_function_name, None) validate_function = getattr(obj_class, validate_function_name, None)
if validate_function is not None: if validate_function is not None:
@ -770,6 +769,8 @@ async def validate_inputs(prompt_id, prompt, item, validated):
validate_has_kwargs = argspec.varkw is not None validate_has_kwargs = argspec.varkw is not None
received_types = {} received_types = {}
valid_inputs = set(class_inputs.get('required',{})).union(set(class_inputs.get('optional',{})))
for x in valid_inputs: for x in valid_inputs:
input_type, input_category, extra_info = get_input_info(obj_class, x, class_inputs) input_type, input_category, extra_info = get_input_info(obj_class, x, class_inputs)
assert extra_info is not None assert extra_info is not None