From 088778c35d4e53dd4c81bb2fc07f7a9999103e5c Mon Sep 17 00:00:00 2001 From: xmarre Date: Sun, 15 Mar 2026 17:06:20 +0100 Subject: [PATCH] Stop canonicalizing is_changed --- comfy_execution/caching.py | 21 +++++++++++++++++++-- tests-unit/execution_test/caching_test.py | 9 +++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/comfy_execution/caching.py b/comfy_execution/caching.py index ca8b15918..d3a7ec52a 100644 --- a/comfy_execution/caching.py +++ b/comfy_execution/caching.py @@ -283,6 +283,10 @@ def to_hashable(obj, max_nodes=_MAX_SIGNATURE_CONTAINER_VISITS): return value return memo.get(id(value), Unhashable()) + def is_failed(value): + """Return whether a resolved child value represents failed canonicalization.""" + return type(value) is Unhashable + def resolve_unordered_values(current_items, container_tag): """Resolve a set-like container or fail closed if ordering is ambiguous.""" try: @@ -290,6 +294,8 @@ def to_hashable(obj, max_nodes=_MAX_SIGNATURE_CONTAINER_VISITS): (_sanitized_sort_key(item, memo=sort_memo), resolve_value(item)) for item in current_items ] + if any(is_failed(value) for _, value in ordered_items): + return Unhashable() ordered_items.sort(key=lambda item: item[0]) except RuntimeError: return Unhashable() @@ -327,6 +333,9 @@ def to_hashable(obj, max_nodes=_MAX_SIGNATURE_CONTAINER_VISITS): (_sanitized_sort_key(k, memo=sort_memo), resolve_value(k), resolve_value(v)) for k, v in items ] + if any(is_failed(key) or is_failed(value) for _, key, value in ordered_items): + memo[current_id] = Unhashable() + continue ordered_items.sort(key=lambda item: item[0]) for index in range(1, len(ordered_items)): if ordered_items[index - 1][0] == ordered_items[index][0]: @@ -341,12 +350,20 @@ def to_hashable(obj, max_nodes=_MAX_SIGNATURE_CONTAINER_VISITS): items = snapshots.pop(current_id, None) if items is None: items = list(current) - memo[current_id] = ("list", tuple(resolve_value(item) for item in items)) + resolved_items = tuple(resolve_value(item) for item in items) + if any(is_failed(item) for item in resolved_items): + memo[current_id] = Unhashable() + else: + memo[current_id] = ("list", resolved_items) elif current_type is tuple: items = snapshots.pop(current_id, None) if items is None: items = list(current) - memo[current_id] = ("tuple", tuple(resolve_value(item) for item in items)) + resolved_items = tuple(resolve_value(item) for item in items) + if any(is_failed(item) for item in resolved_items): + memo[current_id] = Unhashable() + else: + memo[current_id] = ("tuple", resolved_items) elif current_type is set: items = snapshots.pop(current_id, None) if items is None: diff --git a/tests-unit/execution_test/caching_test.py b/tests-unit/execution_test/caching_test.py index c96f40722..943f72586 100644 --- a/tests-unit/execution_test/caching_test.py +++ b/tests-unit/execution_test/caching_test.py @@ -205,6 +205,15 @@ def test_to_hashable_handles_shared_builtin_substructures(caching_module): assert hashable[1][0][0] == "list" +def test_to_hashable_fails_closed_for_ordered_container_with_opaque_child(caching_module): + """Ordered containers should fail closed when a child cannot be canonicalized.""" + caching, _ = caching_module + + result = caching.to_hashable([object()]) + + assert isinstance(result, caching.Unhashable) + + def test_to_hashable_canonicalizes_dict_insertion_order(caching_module): """Dicts with the same content should hash identically regardless of insertion order.""" caching, _ = caching_module