Package: cache-house
Caching tool for python, working with Redis single instance and Redis cluster modePyPi linkInstallation$pipinstallcache-houseor with poetrypoetryaddcache-houseQuick Startcache decorator work with async and sync functionsfromcache_house.backendsimportRedisFactoryfromcache_house.cacheimportcacheimportasyncioRedisFactory.init()@cache()# default expire time is 180 secondsasyncdeftest_cache(a:int,b:int):print("async cached")return[a,b]@cache()deftest_cache_1(a:int,b:int):print("cached")return[a,b]if__name__=="__main__":print(test_cache_1(3,4))print(asyncio.run(test_cache(1,2)))Check stored cache key➜$rdcliKEYS"*"1)cachehouse:main:8f65aed1010f0062a783c83eb430aca02)cachehouse:main:f665833ea64e4fc32653df794257ca06Setup Redis cache instanceYou can pass allredis-pyarguments to  RedisCache.init method and additional arguments :defRedisFactory.init(host:str="localhost",port:int=6379,encoder:Callable[...,Any]=...,decoder:Callable[...,Any]=...,namespace:str=...,key_prefix:str=...,key_builder:Callable[...,Any]=...,password:str=...,db:int=...,cluster_mode:bool=False**redis_kwargs)or you can set your own encoder and decoder functionsfromcache_house.backendsimportRedisFactorydefcustom_encoder(data):returnjson.dumps(data)defcustom_decoder(data):returnjson.loads(data)RedisFactory.init(encoder=custom_encoder,decoder=custom_decoder)Default encoder and decoder is pickle module.Setup Redis Cluster cache instanceAll manipulation with RedisCache  same with a RedisClusterCachefromcache_house.backendsimportRedisFactoryfromcache_house.cacheimportcacheRedisFactory.init(cluster_mode=True)@cache()asyncdeftest_cache(a:int,b:int):print("cached")return[a,b]defRedisFactory.init(# for redis clustercls,host="localhost",port=6379,encoder:Callable[...,Any]=pickle_encoder,decoder:Callable[...,Any]=pickle_decoder,namespace:str=DEFAULT_NAMESPACE,key_prefix:str=DEFAULT_PREFIX,key_builder:Callable[...,Any]=key_builder,cluster_mode:bool=False,startup_nodes=None,cluster_error_retry_attempts:int=3,require_full_coverage:bool=True,skip_full_coverage_check:bool=False,reinitialize_steps:int=10,read_from_replicas:bool=False,)Setup cache instance with FastAPIimportloggingimportuvicornfromfastapi.applicationsimportFastAPIfromcache_house.backendsimportRedisFactoryfromcache_house.cacheimportcacheapp=FastAPI()@app.on_event("startup")asyncdefstartup():print("app started")RedisFactory.init()@app.on_event("shutdown")asyncdefshutdown():print("SHUTDOWN")RedisFactory.close_connections()@app.get("/notcached")asyncdeftest_route():print("notcached")return{"hello":"world"}@app.get("/cached")@cache()asyncdeftest_route():print("cached")# second time when you request this print is not workingreturn{"hello":"world"}if__name__=="__main__":uvicorn.run(app,port=8033)You can set expire time (seconds) , namespace and key prefix in cache decorator@cache(expire=30,namespace="app",key_prefix="test")asyncdeftest_cache(a:int,b:int):print("cached")return[a,b]if__name__=="__main__":print(asyncio.run(test_cache(1,2)))Check stored cacherdcliKEYS"*"1)test:app:f665833ea64e4fc32653df794257ca06If your function works with non-standard data types, you can pass custom encoder and decoder functions to thecachedecorator.importasyncioimportjsonfromcache_house.backendsimportRedisFactoryfromcache_house.cacheimportcacheRedisFactory.init()defcustom_encoder(data):returnjson.dumps(data)defcustom_decoder(data):returnjson.loads(data)@cache(expire=30,encoder=custom_encoder,decoder=custom_decoder,namespace="custom")asyncdeftest_cache(a:int,b:int):print("async cached")return{"a":a,"b":b}@cache(expire=30)deftest_cache_1(a:int,b:int):print("cached")return[a,b]if__name__=="__main__":print(asyncio.run(test_cache(1,2)))print(test_cache_1(3,4))Check stored cacherdcliKEYS"*"1)cachehouse:main:8f65aed1010f0062a783c83eb430aca02)cachehouse:custom:f665833ea64e4fc32653df794257ca06All examples works fine with Redis Cluster and single Redis instance.ContributingFree to open issue and send PRcache-house  supports Python >= 3.7