Package: impcache
impcacheSimple async cache with high performance. Easy to use & ready for production.UsageCache backendimpcache usesRedisas a cache backend. To begin you’ll need a Redis server
running either locally or on a remote machine.DependenciesUnder the hood, impcache uses asyncredis-pywith hiredis support
for faster performance. For serialization and deserialization we're usingorjson- the fastest Python library for JSON
(benchmarks).InstallTo install a wheel from PyPI:pipinstall--upgradeimpcacheQuickstartThis is an example of setting and getting key from cache:importasynciofromimpcacheimportCache,RedisCacheRepositoryasyncdefmain():cache=Cache(repository=RedisCacheRepository(dsn="redis://redis:6379/0"),key_prefix="cache",version=1,)awaitcache.set("key","value",expire=100)result=awaitcache.get("key")print(result)if__name__=="__main__":asyncio.run(main())Cache argumentsCache can be configured to control caching behavior. These settings are provided as arguments for the Cache class.
Valid arguments are as follows:repository: OnlyRedisCacheRepositorysupported at the moment.key_prefix: A string that will be automatically prepended to all cache keys.
See thecache key prefixingfor more information.version: The default version number generated for cache keys (can be string or integer).
See thecache versioningfor more information.Cache key prefixingTo prevent cache key collision, impcache provides the ability to prefix all cache keys. When a particular cache key
is saved or retrieved, impcache will automatically prefix the cache key with the value of thekey_prefixargument.Cache versioningWhen you change running code that uses cached values, you may need to purge any existing cached values.
The easiest way to do this is to use the version identifier, specified using theversionargument for the Cache
class or on primitive cache functions level.By default, any key automatically includes the version "1".For example:>>># Set version 2 of a cache key>>>awaitcache.set("key","value",expire=100,version=2)>>># Get the default version (assuming version=1)>>>awaitcache.get("key")None# Get version 2 of the same key>>>awaitcache.get("key",version=2)valueCache key formatAs described in the previous two sections, the cache key provided by a user is not used verbatim – it is combined
with the cache prefix and key version to provide a final cache key. By default, the three parts are joined
using colons to produce a final string:f"{key_prefix}:{key_version}:{key}"Cache APIset(key: str, value: JSON, expire: int, version: Optional[int | str] = None) -> Literal[True]:Sets the value at key name to value with expiration.>>>awaitcache.set("key","value",expire=100)Trueset_nx(key: str, value: JSON, expire: int, version: Optional[int | str] = None) -> bool:Sets the value at key name to value with expiration only if key does not exist.
Returns False if key exists, True otherwise.>>>awaitcache.set_nx("key","value",expire=100)True>>>awaitcache.set_nx("key","value",expire=100)Falseset_many(data: dict[str, JSON], expire: int, version: Optional[int | str] = None) -> Literal[True]:Sets key/values based on a dictionary of key-value pairs.>>>awaitcache.set_many({"key1":"value1","key2":"value2"},expire=100)Trueget(key: str, version: Optional[int | str] = None) -> Optional[JSON]:Returns the value at key name, or None if the key doesn't exist.>>>awaitcache.set("key","value",expire=100)True>>>awaitcache.get("key")value>>>awaitcache.get("non-existing-key")Noneget_many(keys: list[str], version: Optional[int | str] = None) -> list[Optional[JSON]]:Returns a list of values ordered identically to keys, for every key that does not hold a value or does not exist,
None is returned.>>>awaitcache.set_many({"key1":"value1","key2":"value2"},expire=100)True>>>awaitcache.get_many(["key1","non-existing-key","key2"])["value1",None,"value2"]delete(key: str, version: Optional[int | str] = None) -> int:Deletes the key, returns the number of keys removed.>>>awaitcache.set("key","value",expire=100)True>>>awaitcache.delete("key")1delete_many(keys: list[str], version: Optional[int | str] = None) -> int:Deletes keys specified by keys list, returns the number of keys removed.>>>awaitcache.set_many({"key1":"value1","key2":"value2"},expire=100)True>>>awaitcache.delete_many(["key1","non-existing-key","key2"])2delete_pattern(pattern: str, version: Optional[int | str] = None) -> int:Deletes keys specified by pattern, returns the number of keys removed.Supported patterns:h?llo matches hello, hallo and hxlloh*llo matches hllo and heeeelloh[ae]llo matches hello and hallo, but not hilloh[^e]llo matches hallo, hbllo, ... but not helloh[a-b]llo matches hallo and hbllo>>>awaitcache.set_many({"hllo":"value1","heeeello":"value2"},expire=100)True>>># h*llo matches hllo and heeeello>>>awaitcache.delete_pattern("h*llo")2ExamplesFastAPIAll dependencies should be async to avoid running in the external threadpool, even if they just return an instance.
See theFastAPI dependenciesdocumentation for more information.depencies.py:fromimpcacheimportCache,RedisCacheRepositoryasyncdefcache_dependency()->Cache:returnCache(repository=RedisCacheRepository(dsn="redis://redis:6379/0"),key_prefix="cache",version=1,)api.py:fromfastapiimportAPIRouter,DependsfromimpcacheimportICachefrom.depenciesimportcache_dependencyrouter=APIRouter()@router.get("/test-cache")asyncdeftest_cache(cache:ICache=Depends(cache_dependency),):awaitcache.set("key","value",expire=100)cached_value=awaitcache.get("key")return{"cached_value":cached_value}LicenseThis project is licensed under the terms of the MIT license.