Elaborate a little more in the warning message for `config.cache`

This commit is contained in:
Adam Turner 2024-04-17 21:24:11 +01:00
parent af271881e2
commit 141f3ecdf3
2 changed files with 15 additions and 16 deletions

View File

@ -51,30 +51,28 @@ class ConfigValue(NamedTuple):
rebuild: _ConfigRebuild
def is_serializable(obj: object, *, _recursive_guard: frozenset[int] = frozenset()) -> bool:
"""Check if object is serializable or not."""
def is_serializable(obj: object, *, _seen: frozenset[int] = frozenset()) -> bool:
"""Check if an object is serializable or not."""
if isinstance(obj, UNSERIALIZABLE_TYPES):
return False
# use id() to handle un-hashable objects
if id(obj) in _recursive_guard:
if id(obj) in _seen:
return True
if isinstance(obj, dict):
guard = _recursive_guard | {id(obj)}
for key, value in obj.items():
if (
not is_serializable(key, _recursive_guard=guard)
or not is_serializable(value, _recursive_guard=guard)
):
return False
seen = _seen | {id(obj)}
return all(
is_serializable(key, _seen=seen) and is_serializable(value, _seen=seen)
for key, value in obj.items()
)
elif isinstance(obj, (list, tuple, set, frozenset)):
guard = _recursive_guard | {id(obj)}
return all(is_serializable(item, _recursive_guard=guard) for item in obj)
seen = _seen | {id(obj)}
return all(is_serializable(item, _seen=seen) for item in obj)
# if an issue occurs for a non-serializable type, pickle will complain
# since the object is likely coming from a third-party extension (we
# natively expect 'simple' types and not weird ones)
# since the object is likely coming from a third-party extension
# (we natively expect 'simple' types and not weird ones)
return True
@ -473,7 +471,8 @@ class Config:
# will always mark the config value as changed,
# and thus always invalidate the cache and perform a rebuild.
logger.warning(
__('cannot cache unpickable configuration value: %r'),
__('cannot cache unpickable configuration value: %r '
'(because it contains a function, class, or module object)'),
name,
type='config',
subtype='cache',

View File

@ -46,7 +46,7 @@ def check_is_serializable(subject: object, *, circular: bool) -> None:
# check that without recursive guards, a recursion error occurs
with pytest.raises(RecursionError):
assert is_serializable(subject, _recursive_guard=UselessGuard())
assert is_serializable(subject, _seen=UselessGuard())
def test_is_serializable() -> None: