Stop canonicalizing dict keys

This commit is contained in:
xmarre 2026-03-16 16:48:42 +01:00
parent 1a00f7743f
commit ce05e377a8
3 changed files with 42 additions and 10 deletions

View File

@ -467,9 +467,15 @@ class CacheKeySetInputSignature(CacheKeySet):
"""Build the full cache signature for a node and its ordered ancestors."""
signature = []
ancestors, order_mapping = self.get_ordered_ancestry(dynprompt, node_id)
signature.append(await self.get_immediate_node_signature(dynprompt, node_id, order_mapping))
immediate = await self.get_immediate_node_signature(dynprompt, node_id, order_mapping)
if type(immediate) is Unhashable:
return immediate
signature.append(immediate)
for ancestor_id in ancestors:
signature.append(await self.get_immediate_node_signature(dynprompt, ancestor_id, order_mapping))
immediate = await self.get_immediate_node_signature(dynprompt, ancestor_id, order_mapping)
if type(immediate) is Unhashable:
return immediate
signature.append(immediate)
return tuple(signature)
async def get_immediate_node_signature(self, dynprompt, node_id, ancestor_order_mapping):
@ -485,7 +491,10 @@ class CacheKeySetInputSignature(CacheKeySet):
node = dynprompt.get_node(node_id)
class_type = node["class_type"]
class_def = nodes.NODE_CLASS_MAPPINGS[class_type]
signature = [class_type, _shallow_is_changed_signature(await self.is_changed_cache.get(node_id))]
is_changed_signature = _shallow_is_changed_signature(await self.is_changed_cache.get(node_id))
if type(is_changed_signature) is Unhashable:
return is_changed_signature
signature = [class_type, is_changed_signature]
if self.include_node_id_in_input() or (hasattr(class_def, "NOT_IDEMPOTENT") and class_def.NOT_IDEMPOTENT) or include_unique_id_in_input(class_type):
signature.append(node_id)
inputs = node["inputs"]
@ -495,7 +504,10 @@ class CacheKeySetInputSignature(CacheKeySet):
ancestor_index = ancestor_order_mapping[ancestor_id]
signature.append((key,("ANCESTOR", ancestor_index, ancestor_socket)))
else:
signature.append((key, to_hashable(inputs[key])))
value_signature = to_hashable(inputs[key])
if type(value_signature) is Unhashable:
return value_signature
signature.append((key, value_signature))
return tuple(signature)
# This function returns a list of all ancestors of the given node. The order of the list is

View File

@ -386,8 +386,8 @@ def test_shallow_is_changed_signature_fails_closed_for_opaque_payload(caching_mo
assert isinstance(sanitized, caching.Unhashable)
def test_get_immediate_node_signature_marks_recursive_is_changed_unhashable(caching_module, monkeypatch):
"""Recursive `is_changed` payloads should be cut off before signature canonicalization."""
def test_get_immediate_node_signature_fails_closed_for_unhashable_is_changed(caching_module, monkeypatch):
"""Recursive `is_changed` payloads should fail the full fragment closed."""
caching, nodes_module = caching_module
monkeypatch.setitem(nodes_module.NODE_CLASS_MAPPINGS, "UnitTestNode", _DummyNode)
@ -409,4 +409,4 @@ def test_get_immediate_node_signature_marks_recursive_is_changed_unhashable(cach
signature = asyncio.run(key_set.get_immediate_node_signature(dynprompt, "node", {}))
assert isinstance(signature[1], caching.Unhashable)
assert isinstance(signature, caching.Unhashable)

View File

@ -84,9 +84,29 @@ def test_get_immediate_node_signature_fails_closed_for_opaque_non_link_input(mon
keyset = caching.CacheKeySetInputSignature(dynprompt, [], _StubIsChangedCache())
signature = asyncio.run(keyset.get_immediate_node_signature(dynprompt, "1", {}))
assert signature[:2] == ("TestCacheNode", None)
assert signature[2][0] == "value"
assert type(signature[2][1]) is caching.Unhashable
assert isinstance(signature, caching.Unhashable)
def test_get_node_signature_propagates_unhashable_immediate_fragment(monkeypatch):
class OpaqueRuntimeValue:
pass
dynprompt = _StubDynPrompt(
{
"1": {
"class_type": "TestCacheNode",
"inputs": {"value": OpaqueRuntimeValue()},
}
}
)
monkeypatch.setitem(caching.nodes.NODE_CLASS_MAPPINGS, "TestCacheNode", _StubNode)
monkeypatch.setattr(caching, "NODE_CLASS_CONTAINS_UNIQUE_ID", {})
keyset = caching.CacheKeySetInputSignature(dynprompt, [], _StubIsChangedCache())
signature = asyncio.run(keyset.get_node_signature(dynprompt, "1"))
assert isinstance(signature, caching.Unhashable)
def test_get_node_signature_never_visits_raw_non_link_input(monkeypatch):