* fix: release 3.2.3 — metadata parsing, null-safe saves, auto-hide, tag search - fix(#75): stop SaveImage patch from writing the last-run prompt into every PromptManager node (negative prompts were saved as copies of the positive) - fix(#75): replace four duplicated metadata parsers with a shared web/js/comfy-metadata.js that traces sampler links (KSampler, CFGGuider / SamplerCustomAdvanced, LoRA chains, ControlNet pass-through, any checkpoint loader) and recovers per-node text for images saved by older versions - fix(#143): treat null JSON body fields as empty in prompt API handlers - fix(#149): keep auto-hide timeout 0 (disabled) instead of falling back to the default; validate result_timeout on save - feat(#150): support tag:name filters in the node search box - docs(#142): scan dialog mentions A1111/Forge metadata support - docs(#144): fix ComfyUI-Lora-Manager links - ci: run JS tests with node --test * fix: bound metadata graph traversal to prevent tab freeze on crafted PNGs Link resolution tried every linked input recursively with only a depth cap, so a PNG whose prompt graph has cycles and fan-out could force ~inputs^25 paths and hang the gallery/metadata page. Each lookup now shares a visited set (each node expanded once) with a hard cap of 500 visits. * fix: read the matching output of multi-output settings nodes KSampler settings linked to a node like SamplerCombo all resolved to its first value, so steps, cfg and sampler showed the sampler name. Scalar resolution now prefers the linked node's input with the same field name. * fix: address review — trust API text, restore workflow-only parsing - Workflow widget text now only replaces API text for metadata showing the pre-3.2.3 corruption signature (2+ PromptManager nodes with identical API text but different widgets). Otherwise the API graph wins, so expanded dynamic prompts and linked text display what actually ran. - Images with only a UI workflow are converted to the API graph shape and traced the same way: prompts, KSamplerAdvanced, UNET/checkpoint loaders, KJNodes Set/Get, Reroute, bypassed and muted nodes.
70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
"""Tests for utils.comfyui_integration."""
|
|
|
|
import os
|
|
import sys
|
|
import types
|
|
import unittest
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from utils.comfyui_integration import ComfyUIMetadataIntegration
|
|
|
|
|
|
class TestSaveImageNotPatched(unittest.TestCase):
|
|
"""Regression for #75: SaveImage must save each node's own prompt inputs.
|
|
|
|
The old SaveImage patch wrote the last-run PromptManager prompt into every
|
|
PromptManager node, so negative prompts were saved as copies of the positive.
|
|
"""
|
|
|
|
def setUp(self):
|
|
def save_images(
|
|
self_node,
|
|
images,
|
|
filename_prefix="ComfyUI",
|
|
prompt=None,
|
|
extra_pnginfo=None,
|
|
):
|
|
return {"prompt": prompt}
|
|
|
|
self.original_save_images = save_images
|
|
fake_nodes = types.ModuleType("nodes")
|
|
fake_nodes.SaveImage = type("SaveImage", (), {"save_images": save_images})
|
|
self._saved_nodes = sys.modules.get("nodes")
|
|
sys.modules["nodes"] = fake_nodes
|
|
self.fake_nodes = fake_nodes
|
|
ComfyUIMetadataIntegration._instance = None
|
|
|
|
def tearDown(self):
|
|
ComfyUIMetadataIntegration._instance = None
|
|
if self._saved_nodes is None:
|
|
sys.modules.pop("nodes", None)
|
|
else:
|
|
sys.modules["nodes"] = self._saved_nodes
|
|
|
|
def test_save_images_is_left_untouched(self):
|
|
ComfyUIMetadataIntegration()
|
|
self.assertIs(self.fake_nodes.SaveImage.save_images, self.original_save_images)
|
|
|
|
def test_registered_prompt_does_not_rewrite_saved_metadata(self):
|
|
integration = ComfyUIMetadataIntegration()
|
|
integration.register_prompt("pm_1", "positive final text", {})
|
|
prompt = {
|
|
"39": {"class_type": "PromptManager", "inputs": {"text": "a cat"}},
|
|
"40": {"class_type": "PromptManager", "inputs": {"text": "blurry"}},
|
|
}
|
|
|
|
result = self.fake_nodes.SaveImage().save_images([], prompt=prompt)
|
|
|
|
self.assertEqual(result["prompt"]["39"]["inputs"]["text"], "a cat")
|
|
self.assertEqual(result["prompt"]["40"]["inputs"]["text"], "blurry")
|
|
|
|
def test_prompt_registry_still_available_to_nodes(self):
|
|
integration = ComfyUIMetadataIntegration()
|
|
integration.register_prompt("pm_1", "hello", {})
|
|
self.assertEqual(integration.get_current_prompt_text("pm_1"), "hello")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|