mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-03-06 09:47:35 +08:00
feat: add minLength/maxLength validation for String inputs
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Build package / Build Test (3.10) (push) Has been cancelled
Build package / Build Test (3.11) (push) Has been cancelled
Build package / Build Test (3.12) (push) Has been cancelled
Build package / Build Test (3.13) (push) Has been cancelled
Build package / Build Test (3.14) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Build package / Build Test (3.10) (push) Has been cancelled
Build package / Build Test (3.11) (push) Has been cancelled
Build package / Build Test (3.12) (push) Has been cancelled
Build package / Build Test (3.13) (push) Has been cancelled
Build package / Build Test (3.14) (push) Has been cancelled
This commit is contained in:
parent
afb54219fa
commit
2500d0fcfb
@ -326,11 +326,14 @@ class String(ComfyTypeIO):
|
|||||||
'''String input.'''
|
'''String input.'''
|
||||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
||||||
multiline=False, placeholder: str=None, default: str=None, dynamic_prompts: bool=None,
|
multiline=False, placeholder: str=None, default: str=None, dynamic_prompts: bool=None,
|
||||||
|
min_length: int=None, max_length: int=None,
|
||||||
socketless: bool=None, force_input: bool=None, extra_dict=None, raw_link: bool=None, advanced: bool=None):
|
socketless: bool=None, force_input: bool=None, extra_dict=None, raw_link: bool=None, advanced: bool=None):
|
||||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input, extra_dict, raw_link, advanced)
|
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input, extra_dict, raw_link, advanced)
|
||||||
self.multiline = multiline
|
self.multiline = multiline
|
||||||
self.placeholder = placeholder
|
self.placeholder = placeholder
|
||||||
self.dynamic_prompts = dynamic_prompts
|
self.dynamic_prompts = dynamic_prompts
|
||||||
|
self.min_length = min_length
|
||||||
|
self.max_length = max_length
|
||||||
self.default: str
|
self.default: str
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
@ -338,6 +341,8 @@ class String(ComfyTypeIO):
|
|||||||
"multiline": self.multiline,
|
"multiline": self.multiline,
|
||||||
"placeholder": self.placeholder,
|
"placeholder": self.placeholder,
|
||||||
"dynamicPrompts": self.dynamic_prompts,
|
"dynamicPrompts": self.dynamic_prompts,
|
||||||
|
"minLength": self.min_length,
|
||||||
|
"maxLength": self.max_length,
|
||||||
})
|
})
|
||||||
|
|
||||||
@comfytype(io_type="COMBO")
|
@comfytype(io_type="COMBO")
|
||||||
|
|||||||
65
execution.py
65
execution.py
@ -215,6 +215,41 @@ def get_input_data(inputs, class_def, unique_id, execution_list=None, dynprompt=
|
|||||||
v3_data["hidden_inputs"] = hidden_inputs_v3
|
v3_data["hidden_inputs"] = hidden_inputs_v3
|
||||||
return input_data_all, missing_keys, v3_data
|
return input_data_all, missing_keys, v3_data
|
||||||
|
|
||||||
|
def validate_resolved_inputs(input_data_all, class_def, inputs):
|
||||||
|
"""Validate resolved input values against schema constraints.
|
||||||
|
|
||||||
|
This is needed because validate_inputs() only sees direct widget values.
|
||||||
|
Linked inputs aren't resolved during validate_inputs(), so this runs after resolution to catch any violations.
|
||||||
|
"""
|
||||||
|
is_v3 = issubclass(class_def, _ComfyNodeInternal)
|
||||||
|
valid_inputs = class_def.INPUT_TYPES()
|
||||||
|
if is_v3:
|
||||||
|
valid_inputs, _, _ = _io.get_finalized_class_inputs(valid_inputs, inputs)
|
||||||
|
|
||||||
|
for x, values in input_data_all.items():
|
||||||
|
input_type, input_category, extra_info = get_input_info(class_def, x, valid_inputs)
|
||||||
|
if extra_info is None:
|
||||||
|
continue
|
||||||
|
if input_type != "STRING":
|
||||||
|
continue
|
||||||
|
min_length = extra_info.get("minLength")
|
||||||
|
max_length = extra_info.get("maxLength")
|
||||||
|
if min_length is None and max_length is None:
|
||||||
|
continue
|
||||||
|
for val in values:
|
||||||
|
if val is None or not isinstance(val, str):
|
||||||
|
continue
|
||||||
|
if min_length is not None and len(val) < min_length:
|
||||||
|
raise ValueError(
|
||||||
|
f"Input '{x}': value length {len(val)} is shorter than "
|
||||||
|
f"minimum length of {min_length}"
|
||||||
|
)
|
||||||
|
if max_length is not None and len(val) > max_length:
|
||||||
|
raise ValueError(
|
||||||
|
f"Input '{x}': value length {len(val)} is longer than "
|
||||||
|
f"maximum length of {max_length}"
|
||||||
|
)
|
||||||
|
|
||||||
map_node_over_list = None #Don't hook this please
|
map_node_over_list = None #Don't hook this please
|
||||||
|
|
||||||
async def resolve_map_node_over_list_results(results):
|
async def resolve_map_node_over_list_results(results):
|
||||||
@ -498,6 +533,8 @@ async def execute(server, dynprompt, caches, current_item, extra_data, executed,
|
|||||||
execution_list.make_input_strong_link(unique_id, i)
|
execution_list.make_input_strong_link(unique_id, i)
|
||||||
return (ExecutionResult.PENDING, None, None)
|
return (ExecutionResult.PENDING, None, None)
|
||||||
|
|
||||||
|
validate_resolved_inputs(input_data_all, class_def, inputs)
|
||||||
|
|
||||||
def execution_block_cb(block):
|
def execution_block_cb(block):
|
||||||
if block.message is not None:
|
if block.message is not None:
|
||||||
mes = {
|
mes = {
|
||||||
@ -938,6 +975,34 @@ async def validate_inputs(prompt_id, prompt, item, validated):
|
|||||||
errors.append(error)
|
errors.append(error)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if input_type == "STRING":
|
||||||
|
if "minLength" in extra_info and len(val) < extra_info["minLength"]:
|
||||||
|
error = {
|
||||||
|
"type": "value_shorter_than_min_length",
|
||||||
|
"message": "Value length {} shorter than min length of {}".format(len(val), extra_info["minLength"]),
|
||||||
|
"details": f"{x}",
|
||||||
|
"extra_info": {
|
||||||
|
"input_name": x,
|
||||||
|
"input_config": info,
|
||||||
|
"received_value": val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.append(error)
|
||||||
|
continue
|
||||||
|
if "maxLength" in extra_info and len(val) > extra_info["maxLength"]:
|
||||||
|
error = {
|
||||||
|
"type": "value_longer_than_max_length",
|
||||||
|
"message": "Value length {} longer than max length of {}".format(len(val), extra_info["maxLength"]),
|
||||||
|
"details": f"{x}",
|
||||||
|
"extra_info": {
|
||||||
|
"input_name": x,
|
||||||
|
"input_config": info,
|
||||||
|
"received_value": val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.append(error)
|
||||||
|
continue
|
||||||
|
|
||||||
if isinstance(input_type, list) or input_type == io.Combo.io_type:
|
if isinstance(input_type, list) or input_type == io.Combo.io_type:
|
||||||
if input_type == io.Combo.io_type:
|
if input_type == io.Combo.io_type:
|
||||||
combo_options = extra_info.get("options", [])
|
combo_options = extra_info.get("options", [])
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user