diff --git a/comfy_execution/caching.py b/comfy_execution/caching.py index fecf54d1e..1a5615627 100644 --- a/comfy_execution/caching.py +++ b/comfy_execution/caching.py @@ -68,15 +68,17 @@ _FAILED_SIGNATURE = object() def _shallow_is_changed_signature(value): - """Sanitize execution-time `is_changed` values with a small fail-closed budget.""" + """Reduce execution-time `is_changed` values through a fail-closed builtin canonicalizer.""" value_type = type(value) if value_type in _PRIMITIVE_SIGNATURE_TYPES: return value - canonical = to_hashable(value, max_nodes=64) + if value_type not in _CONTAINER_SIGNATURE_TYPES: + return Unhashable() + + canonical = _signature_to_hashable(value, max_nodes=64) if type(canonical) is Unhashable: return canonical - if value_type is list or value_type is tuple: container_tag = "is_changed_list" if value_type is list else "is_changed_tuple" return (container_tag, canonical[1]) diff --git a/tests/execution/test_caching.py b/tests/execution/test_caching.py index 569bf5bd8..765ab0b91 100644 --- a/tests/execution/test_caching.py +++ b/tests/execution/test_caching.py @@ -25,6 +25,50 @@ class _StubNode: return {"required": {}} +def test_shallow_is_changed_signature_keeps_primitive_only_list_shallow(): + assert caching._shallow_is_changed_signature([1, "two", None, True]) == ( + "is_changed_list", + (1, "two", None, True), + ) + + +def test_shallow_is_changed_signature_keeps_primitive_only_tuple_shallow(): + assert caching._shallow_is_changed_signature((1, "two", None, True)) == ( + "is_changed_tuple", + (1, "two", None, True), + ) + + +def test_shallow_is_changed_signature_keeps_structured_builtin_fingerprint_list(): + assert caching._shallow_is_changed_signature([("seed", 42), {"cfg": 8}]) == ( + "is_changed_list", + ( + ("tuple", ("seed", 42)), + ("dict", (("cfg", 8),)), + ), + ) + + +def test_shallow_is_changed_signature_does_not_use_to_hashable(monkeypatch): + monkeypatch.setattr( + caching, + "to_hashable", + lambda *_args, **_kwargs: (_ for _ in ()).throw( + AssertionError("is_changed signature must not deep-canonicalize") + ), + ) + + signature = caching._shallow_is_changed_signature([("seed", 42), {"cfg": 8}]) + + assert signature == ( + "is_changed_list", + ( + ("tuple", ("seed", 42)), + ("dict", (("cfg", 8),)), + ), + ) + + def test_get_immediate_node_signature_canonicalizes_non_link_inputs(monkeypatch): live_value = [1, {"nested": [2, 3]}] dynprompt = _StubDynPrompt(