Fix shallow is_changed logic

This commit is contained in:
xmarre 2026-03-18 13:15:04 +01:00
parent e13da8104c
commit c702cddf75
2 changed files with 29 additions and 13 deletions

View File

@ -68,22 +68,22 @@ _FAILED_SIGNATURE = object()
def _shallow_is_changed_signature(value):
"""Reduce execution-time `is_changed` values without deep traversal."""
"""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
if value_type is list or value_type is tuple:
try:
items = tuple(value)
except RuntimeError:
return Unhashable()
if all(type(item) in _PRIMITIVE_SIGNATURE_TYPES for item in items):
container_tag = "is_changed_list" if value_type is list else "is_changed_tuple"
return (container_tag, items)
if value_type not in _CONTAINER_SIGNATURE_TYPES:
return Unhashable()
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])
return canonical
def _primitive_signature_sort_key(obj):

View File

@ -39,7 +39,17 @@ def test_shallow_is_changed_signature_keeps_primitive_only_tuple_shallow():
)
def test_shallow_is_changed_signature_fails_closed_for_nested_container(monkeypatch):
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",
@ -48,9 +58,15 @@ def test_shallow_is_changed_signature_fails_closed_for_nested_container(monkeypa
),
)
signature = caching._shallow_is_changed_signature([1, [2, 3]])
signature = caching._shallow_is_changed_signature([("seed", 42), {"cfg": 8}])
assert isinstance(signature, caching.Unhashable)
assert signature == (
"is_changed_list",
(
("tuple", ("seed", 42)),
("dict", (("cfg", 8),)),
),
)
def test_get_immediate_node_signature_canonicalizes_non_link_inputs(monkeypatch):