Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tw9fjV2UVj2u3F3mbnYrQW
74 lines
3.4 KiB
Python
74 lines
3.4 KiB
Python
"""What the loaders present to the graph, and to the person wiring it.
|
|
|
|
These are seam tests, not unit tests: a loader that "loads" is worth nothing if
|
|
what it offers cannot be filled in, or if what it produces is not what the next
|
|
stage reads. No model weights are needed for any of this.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def schemas(comfyui):
|
|
from modules.loaders.clip.nodes import FunUICLIPLoader
|
|
from modules.loaders.diffusion_model.nodes import FunUIDiffusionModelLoader
|
|
from modules.loaders.lora.nodes import FunUILoraLoader
|
|
from modules.loaders.vae.nodes import FunUIVAELoader
|
|
return [FunUICLIPLoader, FunUIDiffusionModelLoader,
|
|
FunUILoraLoader, FunUIVAELoader]
|
|
|
|
|
|
def test_a_file_picker_is_a_widget_not_a_socket(schemas):
|
|
"""The failure this exists for: ComfyUI's autogrow input sets
|
|
force_input=True on any WidgetInput, so a list of Combos renders as a row of
|
|
sockets and the file picker stops being a picker. A dropdown nobody can drop
|
|
down is not a loader."""
|
|
for node in schemas:
|
|
spec = node.INPUT_TYPES()
|
|
for section in ("required", "optional"):
|
|
for name, (kind, options) in (spec.get(section) or {}).items():
|
|
if kind != "COMBO":
|
|
continue
|
|
assert not options.get("forceInput"), (
|
|
f"{node.__name__}.{name} is a COMBO forced to be a socket; "
|
|
f"nobody can pick a file from it"
|
|
)
|
|
|
|
|
|
def test_every_combo_offers_something_to_pick(schemas):
|
|
for node in schemas:
|
|
spec = node.INPUT_TYPES()
|
|
for section in ("required", "optional"):
|
|
for name, (kind, options) in (spec.get(section) or {}).items():
|
|
if kind != "COMBO":
|
|
continue
|
|
assert "options" in options, f"{node.__name__}.{name} has no options at all"
|
|
|
|
|
|
def test_a_default_is_actually_one_of_the_options(schemas):
|
|
"""A default outside its own list makes ComfyUI refuse to queue the whole
|
|
prompt with 'Value not in list' -- and the node looks configured."""
|
|
for node in schemas:
|
|
spec = node.INPUT_TYPES()
|
|
for section in ("required", "optional"):
|
|
for name, (kind, options) in (spec.get(section) or {}).items():
|
|
if kind != "COMBO" or "default" not in options:
|
|
continue
|
|
assert options["default"] in options["options"], (
|
|
f"{node.__name__}.{name} defaults to {options['default']!r}, "
|
|
f"which is not one of its options"
|
|
)
|
|
|
|
|
|
def test_the_lora_loader_asks_for_one_slot_at_a_time(comfyui):
|
|
"""No LoRA picked: only the first picker. A picked LoRA brings its own settings and the next slot's picker."""
|
|
from modules.loaders.lora.nodes import FunUILoraLoader as L
|
|
rules = {i.id: (i.extra_dict or {}).get("funui_shows", []) for i in L.define_schema().inputs}
|
|
assert rules["lora_name"] == []
|
|
assert rules["strength_model"] == [{"input": "lora_name", "not": ["None"]}]
|
|
assert rules["strength_clip_3"] == [{"input": "lora_name_3", "not": ["None"]}]
|
|
assert rules["apply_to_stage_2"] == [{"input": "lora_name_2", "not": ["None"]}]
|
|
ask = rules["lora_name_2"][0]["either"]
|
|
assert [c["input"] for c in ask] == ["lora_name", "lora_name_2"] # after slot 1, or already filled
|
|
assert [c["input"] for c in rules["lora_name_4"][0]["either"]] == ["lora_name_3", "lora_name_4"]
|