Package: pydantic-cache
Pydantic CacheCache results of Python functions, with support for serialization of rich data types powered byPydantic.Supports caching to disk or Redis by default, but additional caching backends can easily be added.ExamplesBasic usageYou can use anydata types which can be serialized by Pydantic, both in the function signature (cache key) and the returned values:fromdatetimeimportdatetime,timedeltafrompydanticimportBaseModelfrompydantic_cacheimportdisk_cacheclassMyModel(BaseModel):a:intb:datetimed:set[datetime]@disk_cache(path="~/.cache/my-function",ttl=timedelta(days=1))defmy_function(date:datetime)->list[MyModel]:return[]# Some expensive computationIn the above example, subsequent calls to the function with the same argument will fetch the results from the cache on disk. Serialization and deserialization are handled based on the function's type annotations.Redis supportThe library includes support for caching results to/from redis. This depends onredis, which can be installed viapip install pydantic-cache[redis].fromdatetimeimporttimedeltafrompydantic_cacheimportcachefrompydantic_cache.backendimportRedisBackendfromredisimportRedisredis=Redis(...)@cache(RedisBackend(redis,ttl=timedelta(days=1)))defmy_function()->dict:return{}Custom cache backendsYou can implement custom cache backends by sub-classingBackend:frompydantic_cacheimportBackend,cacheclassMemoryBackend(Backend):def__init__(self)->None:# Optional initial set-up of the backend.self._cache:dict[str,str]={}defget(self,key:str)->str:# Implement cache retrieval here.# Cache misses should raise a KeyError.returnself._cache[key]defwrite(self,key:str,value:str)->None:# Write to the cache here.self._cache[key]=value@cache(backend=MemoryBackend)defmy_function()->dict:return{}[!NOTE]
Cache backends only interact with serialized data, so thestrtypes above will apply for all backends.Deferred backend resolutionSome backends may rely on reading configurations or creating connections to external services, which is best avoided at import time. To support this, thecachedecorator optionally accepts a callable which returns the backend, instead of the backend itself.fromdatetimeimporttimedeltafrompathlibimportPathfrompydantic_cacheimportDiskBackend,cachefrompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):cache_ttl:timedeltacache_path:Pathdefget_cache_backend()->DiskBackend:settings=Settings()returnDiskBackend(settings.cache_path,ttl=settings.cache_ttl)@cache(backend=get_cache_backend)defmy_function()->dict:return{}asynciosupportAsynchronous functions are supported by default, however using a synchronous backend will naturally result in blocking calls:importasynciofrompydantic_cacheimportDiskBackend,cache@cache(backend=DiskBackend(...))asyncdefmy_function()->dict:returnawaitasyncio.sleep(0,{})To avoid blocking IO calls in the cache backend, you can implement an asynchronous backend as a subclass ofAsyncBackend. See the following example usingaioredis:importasyncioimportaioredisfrompydantic_cacheimportAsyncBackend,cacheclassAioRedisBackend(AsyncBackend):def__init__(self,redis:aioredis.Client)->None:self.redis=redisasyncdefget(self,key:str)->str:result=awaitself.redis.get(key)ifresultisNone:raiseKeyError(key)returnresultasyncdefwrite(self,key:str,value:str)->None:awaitself.redis.set(key,value)@cache(backend=AioRedisBackend(...))asyncdefmy_function()->dict:returnawaitasyncio.sleep(0,{})InstallationThis project is not currently packaged and so must be installed manually.Clone the project with the following command:git clone https://github.com/jacksmith15/pydantic-cache.gitDevelopmentInstall dependencies:pyenvshell3.10.x
pre-commitinstall# Configure commit hookspoetryinstall# Install Python dependenciesRun tests:poetryruninvverifyLicenseThis project is distributed under the MIT license.