From 711907e6ec3db219bd2bebb3272ca3382c01467f Mon Sep 17 00:00:00 2001 From: Jedrzej Kosinski Date: Mon, 20 Apr 2026 19:53:32 -0700 Subject: [PATCH] fix: gate multiselect validation on schema config, improve error message, add tests Amp-Thread-ID: https://ampcode.com/threads/T-019dad04-a07a-724b-af4d-fbfe98654fdd Co-authored-by: Amp --- execution.py | 6 +-- .../multicombo_serialization_test.py | 47 ++++++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/execution.py b/execution.py index 8bce9920c..a520c009d 100644 --- a/execution.py +++ b/execution.py @@ -994,8 +994,8 @@ async def validate_inputs(prompt_id, prompt, item, validated): combo_options = extra_info.get("options", []) else: combo_options = input_type - # MultiCombo sends a list of selected values - if isinstance(val, list): + is_multiselect = extra_info.get("multiselect", False) + if is_multiselect and isinstance(val, list): invalid_vals = [v for v in val if v not in combo_options] else: invalid_vals = [val] if val not in combo_options else [] @@ -1014,7 +1014,7 @@ async def validate_inputs(prompt_id, prompt, item, validated): error = { "type": "value_not_in_list", "message": "Value not in list", - "details": f"{x}: '{invalid_vals}' not in {list_info}", + "details": f"{x}: {', '.join(repr(v) for v in invalid_vals)} not in {list_info}", "extra_info": { "input_name": x, "input_config": input_config, diff --git a/tests-unit/comfy_api_test/multicombo_serialization_test.py b/tests-unit/comfy_api_test/multicombo_serialization_test.py index df925ad19..421c65a0d 100644 --- a/tests-unit/comfy_api_test/multicombo_serialization_test.py +++ b/tests-unit/comfy_api_test/multicombo_serialization_test.py @@ -1,4 +1,4 @@ -from comfy_api.latest._io import MultiCombo +from comfy_api.latest._io import Combo, MultiCombo def test_multicombo_serializes_multi_select_as_object(): @@ -31,3 +31,48 @@ def test_multicombo_serializes_multi_select_with_placeholder_and_chip(): "placeholder": "Select providers", "chip": True, } + + +def test_combo_does_not_serialize_multiselect(): + """Regular Combo should not have multiselect in its serialized output.""" + combo = Combo.Input( + id="choice", + options=["a", "b", "c"], + ) + + serialized = combo.as_dict() + + # Combo sets multiselect=False, but prune_dict keeps False (not None), + # so it should be present but False + assert serialized.get("multiselect") is False + assert "multi_select" not in serialized + + +def _validate_combo_values(val, combo_options, is_multiselect): + """Reproduce the validation logic from execution.py for testing.""" + if is_multiselect and isinstance(val, list): + return [v for v in val if v not in combo_options] + else: + return [val] if val not in combo_options else [] + + +def test_multicombo_validation_accepts_valid_list(): + options = ["a", "b", "c"] + assert _validate_combo_values(["a", "b"], options, True) == [] + + +def test_multicombo_validation_rejects_invalid_values(): + options = ["a", "b", "c"] + assert _validate_combo_values(["a", "x"], options, True) == ["x"] + + +def test_multicombo_validation_accepts_empty_list(): + options = ["a", "b", "c"] + assert _validate_combo_values([], options, True) == [] + + +def test_combo_validation_rejects_list_even_with_valid_items(): + """A regular Combo should not accept a list value.""" + options = ["a", "b", "c"] + invalid = _validate_combo_values(["a", "b"], options, False) + assert len(invalid) > 0