Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .secrets.baseline

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion src/cachekit/cache_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
# Python-specific type tags that no other-language SDK can decode.
CROSS_SDK_SERIALIZER_NAMES = ("default", "std", "standard", "orjson", "arrow")

# Serializer-name aliases collapsed to one canonical frame tag so interchangeable names stay
# cache-compatible: an entry written as 'auto' must read back under 'pythonic' (its documented
# alias) and vice-versa, instead of a serializer-mismatch that recomputes on every read (#167).
_SERIALIZER_NAME_ALIASES = {"std": "default", "standard": "default", "pythonic": "auto"}

# Global DI container instance with default registrations
container = DIContainer()
container.register(LoggerProvider, DefaultLoggerProvider)
Expand Down Expand Up @@ -348,7 +353,7 @@ def __init__(
# Extract string name for metadata storage (for protocol instances, use class name)
if isinstance(serializer_name, str):
# Canonicalize aliases to prevent envelope mismatch on deserialize
self._serializer_string_name = "default" if serializer_name in ("std", "standard") else serializer_name
self._serializer_string_name = _SERIALIZER_NAME_ALIASES.get(serializer_name, serializer_name)
else:
# Protocol instance - use class name for metadata
self._serializer_string_name = type(serializer_name).__name__
Expand Down
43 changes: 43 additions & 0 deletions tests/unit/test_serializer_alias_canonicalization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""`auto` and `pythonic` are documented aliases for the same AutoSerializer (#167).

The handler canonicalized only ``std``/``standard`` -> ``default``, so an entry written with
``serializer="auto"`` stored ``'s':'auto'`` in the frame while a handler configured
``serializer="pythonic"`` compared against the literal ``'pythonic'`` -> serializer-mismatch ->
treated as a miss -> recompute on every read. Both aliases must canonicalize to the same name.
"""

from __future__ import annotations

import pytest

from cachekit.cache_handler import CacheSerializationHandler


@pytest.mark.unit
class TestSerializerAliasCanonicalization:
def test_auto_written_reads_under_pythonic_alias(self) -> None:
payload = {"value": 42, "items": [1, 2, 3]}

wrapped = CacheSerializationHandler(serializer_name="auto").serialize_data(payload, cache_key="k")
result = CacheSerializationHandler(serializer_name="pythonic").deserialize_data(wrapped, cache_key="k")

assert result == payload

def test_pythonic_written_reads_under_auto_alias(self) -> None:
payload = {"value": 42, "items": [1, 2, 3]}

wrapped = CacheSerializationHandler(serializer_name="pythonic").serialize_data(payload, cache_key="k")
result = CacheSerializationHandler(serializer_name="auto").deserialize_data(wrapped, cache_key="k")

assert result == payload

def test_aliases_canonicalize_to_same_stored_name(self) -> None:
# Both aliases must resolve to one canonical frame tag so entries are interchangeable.
auto = CacheSerializationHandler(serializer_name="auto")
pythonic = CacheSerializationHandler(serializer_name="pythonic")
assert auto._serializer_string_name == pythonic._serializer_string_name

def test_std_still_canonicalizes_to_default(self) -> None:
# Guard the pre-existing canonicalization is preserved (only std/default are valid registry names).
for name in ("std", "default"):
assert CacheSerializationHandler(serializer_name=name)._serializer_string_name == "default"
Loading