mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-06-23 16:29:25 +08:00
feat: add --truncate-validation-error-lists to shorten combo validation errors
Combo validation errors include the full list of valid options whenever it has 20 or fewer entries, which can dump an entire folder listing (e.g. a model directory) into the error text. Add an opt-in CLI flag that always replaces the list with the existing short length summary while keeping the input name and the offending value, so errors stay debuggable. Default off: behavior is unchanged unless the flag is set.
This commit is contained in:
parent
28a40fb2b2
commit
6667a7a374
@ -227,6 +227,8 @@ parser.add_argument("--user-directory", type=is_valid_directory, default=None, h
|
||||
|
||||
parser.add_argument("--enable-compress-response-body", action="store_true", help="Enable compressing response body.")
|
||||
|
||||
parser.add_argument("--truncate-validation-error-lists", action="store_true", help="Always replace the list of valid options in 'value not in list' prompt validation errors with a short length summary. By default the full list is included in the error message when it has 20 or fewer entries, which can embed entire folder listings for file/model dropdowns.")
|
||||
|
||||
parser.add_argument(
|
||||
"--comfy-api-base",
|
||||
type=str,
|
||||
|
||||
@ -1,6 +1,27 @@
|
||||
from comfy_api.latest import IO
|
||||
|
||||
|
||||
def format_value_not_in_list_details(input_name, invalid_vals, combo_options, force_truncate=False, max_items=20):
|
||||
"""Build the ``details`` string for a ``value_not_in_list`` validation error.
|
||||
|
||||
Returns a ``(details, truncated)`` tuple. ``details`` always names the
|
||||
offending input and value(s) so the error stays debuggable. The list of
|
||||
valid options is replaced with a short length summary when it has more
|
||||
than ``max_items`` entries (so errors don't embed entire folder listings)
|
||||
or when ``force_truncate`` is set; ``truncated`` is True in that case and
|
||||
callers should also omit the input config from the error, since it
|
||||
contains the same options list.
|
||||
"""
|
||||
if force_truncate or len(combo_options) > max_items:
|
||||
list_info = f"(list of length {len(combo_options)})"
|
||||
truncated = True
|
||||
else:
|
||||
list_info = str(combo_options)
|
||||
truncated = False
|
||||
details = f"{input_name}: {', '.join(repr(v) for v in invalid_vals)} not in {list_info}"
|
||||
return details, truncated
|
||||
|
||||
|
||||
def validate_node_input(
|
||||
received_type: str, input_type: str, strict: bool = False
|
||||
) -> bool:
|
||||
|
||||
20
execution.py
20
execution.py
@ -37,7 +37,7 @@ from comfy_execution.graph import (
|
||||
get_input_info,
|
||||
)
|
||||
from comfy_execution.graph_utils import GraphBuilder, is_link
|
||||
from comfy_execution.validation import validate_node_input
|
||||
from comfy_execution.validation import format_value_not_in_list_details, validate_node_input
|
||||
from comfy_execution.progress import get_progress_state, reset_progress_state, add_progress_handler, WebUIProgressHandler
|
||||
from comfy_execution.utils import CurrentNodeContext
|
||||
from comfy_execution.asset_enrichment import enrich_output_with_assets
|
||||
@ -1043,21 +1043,19 @@ async def validate_inputs(prompt_id, prompt, item, validated, visiting=None):
|
||||
else:
|
||||
invalid_vals = [val] if val not in combo_options else []
|
||||
if invalid_vals:
|
||||
input_config = info
|
||||
list_info = ""
|
||||
|
||||
# Don't send back gigantic lists like if they're lots of
|
||||
# scanned model filepaths
|
||||
if len(combo_options) > 20:
|
||||
list_info = f"(list of length {len(combo_options)})"
|
||||
input_config = None
|
||||
else:
|
||||
list_info = str(combo_options)
|
||||
# scanned model filepaths. The truncated form also omits
|
||||
# the input config, which contains the same options list.
|
||||
details, truncated = format_value_not_in_list_details(
|
||||
x, invalid_vals, combo_options,
|
||||
force_truncate=args.truncate_validation_error_lists,
|
||||
)
|
||||
input_config = None if truncated else info
|
||||
|
||||
error = {
|
||||
"type": "value_not_in_list",
|
||||
"message": "Value not in list",
|
||||
"details": f"{x}: {', '.join(repr(v) for v in invalid_vals)} not in {list_info}",
|
||||
"details": details,
|
||||
"extra_info": {
|
||||
"input_name": x,
|
||||
"input_config": input_config,
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
import pytest
|
||||
|
||||
from comfy.cli_args import parser
|
||||
from comfy_execution.validation import format_value_not_in_list_details
|
||||
|
||||
|
||||
def _legacy_details(input_name, invalid_vals, combo_options):
|
||||
"""The historical details format for short lists, kept byte-identical."""
|
||||
return f"{input_name}: {', '.join(repr(v) for v in invalid_vals)} not in {str(combo_options)}"
|
||||
|
||||
|
||||
def test_short_list_includes_full_options_by_default():
|
||||
options = ["a.safetensors", "b.safetensors"]
|
||||
details, truncated = format_value_not_in_list_details("ckpt_name", ["missing.safetensors"], options)
|
||||
|
||||
assert not truncated
|
||||
assert details == _legacy_details("ckpt_name", ["missing.safetensors"], options)
|
||||
assert "a.safetensors" in details
|
||||
assert "b.safetensors" in details
|
||||
|
||||
|
||||
def test_long_list_is_summarized_by_default():
|
||||
options = [f"model_{i}.safetensors" for i in range(21)]
|
||||
details, truncated = format_value_not_in_list_details("ckpt_name", ["missing.safetensors"], options)
|
||||
|
||||
assert truncated
|
||||
assert details == "ckpt_name: 'missing.safetensors' not in (list of length 21)"
|
||||
assert "model_0.safetensors" not in details
|
||||
|
||||
|
||||
def test_max_items_boundary():
|
||||
at_limit = [f"m{i}" for i in range(20)]
|
||||
details, truncated = format_value_not_in_list_details("ckpt_name", ["nope"], at_limit)
|
||||
assert not truncated
|
||||
assert details == _legacy_details("ckpt_name", ["nope"], at_limit)
|
||||
|
||||
over_limit = at_limit + ["m20"]
|
||||
details, truncated = format_value_not_in_list_details("ckpt_name", ["nope"], over_limit)
|
||||
assert truncated
|
||||
assert "(list of length 21)" in details
|
||||
|
||||
|
||||
def test_force_truncate_summarizes_short_lists():
|
||||
options = ["a.safetensors", "b.safetensors"]
|
||||
details, truncated = format_value_not_in_list_details(
|
||||
"ckpt_name", ["missing.safetensors"], options, force_truncate=True
|
||||
)
|
||||
|
||||
assert truncated
|
||||
assert details == "ckpt_name: 'missing.safetensors' not in (list of length 2)"
|
||||
# The input name and offending value stay in the error so it remains debuggable.
|
||||
assert "ckpt_name" in details
|
||||
assert "missing.safetensors" in details
|
||||
# None of the valid options appear in the error text.
|
||||
assert "a.safetensors" not in details
|
||||
assert "b.safetensors" not in details
|
||||
|
||||
|
||||
@pytest.mark.parametrize("force_truncate", [False, True])
|
||||
def test_multiple_invalid_values_are_preserved(force_truncate):
|
||||
options = ["x", "y"]
|
||||
details, _ = format_value_not_in_list_details(
|
||||
"values", ["bad1", "bad2"], options, force_truncate=force_truncate
|
||||
)
|
||||
|
||||
assert "'bad1', 'bad2'" in details
|
||||
|
||||
|
||||
def test_cli_flag_defaults_off():
|
||||
args = parser.parse_args([])
|
||||
assert args.truncate_validation_error_lists is False
|
||||
|
||||
|
||||
def test_cli_flag_parses_on():
|
||||
args = parser.parse_args(["--truncate-validation-error-lists"])
|
||||
assert args.truncate_validation_error_lists is True
|
||||
Loading…
Reference in New Issue
Block a user