On a miss, get_or_set returns the factory's value as is; on a hit, the JSON-decoded one. The two differ whenever JSON changes the value:
miss: (1, 2) hit: [1, 2]
miss: {1: 'a'} hit: {'1': 'a'}
The first caller sees a tuple and int keys, later callers a list and str keys, so type and key-lookup bugs only appear once the value is cached. For values JSON cannot encode (datetime, Decimal, UUID, pydantic models), the TypeError comes after the possibly expensive factory has run.
Proposal
Return the decoded value on a miss too, so both paths agree, and document the JSON round-trip rules in APP_CACHE.md. Typed reads are a separate enhancement.
On a miss,
get_or_setreturns the factory's value as is; on a hit, the JSON-decoded one. The two differ whenever JSON changes the value:The first caller sees a tuple and int keys, later callers a list and str keys, so type and key-lookup bugs only appear once the value is cached. For values JSON cannot encode (
datetime,Decimal,UUID, pydantic models), theTypeErrorcomes after the possibly expensive factory has run.Proposal
Return the decoded value on a miss too, so both paths agree, and document the JSON round-trip rules in APP_CACHE.md. Typed reads are a separate enhancement.