Package: redis-decorators
Redis DecoratorsRedis cache decorators for automatically caching function return values in Python.Get StartedInstallpip install redis_decoratorsInitializeThe main class,RedisCaching, will initialize Redis for you.from redis_decorators import RedisCaching

caching = RedisCaching('redis://redis:6379')
cache = caching.get_cache()  # Redis instanceUsageThe simplest way to start caching return values is to use one of theRedisCaching.cache_*decorators. The cache key is generated automatically based on the function name and arguments.@caching.cache_string()defmy_string_function(arg1,arg2):# ... do some calculationreturn'my_value'Calculate Cache KeyIf you want to have control over how cache keys are calculated, you can specifyget_cache_keyin the following ways:Lambda function@caching.cache_string(get_cache_key=lambdaarg1:returnf'{arg1}-cache-key')defmy_string_function(arg1):return'my_value'Separate function definitionThe decorator returns a wrapper that allows you to define additional properties:@caching.cache_string()defmy_string_function(arg1):return'my_value'# The cache key function gets the same arguments as the value function.@my_string_function.cache_keydefmy_string_function_cache_key(arg1):returnf'{arg1}-cache-keyKey ExpirationYou can define an expiration time in seconds or with adatetime.timedelta, similar to how you
would define the cache key calculation:# Define a static expiration time with expire_in kwarg:@caching.cache_string(expire_in=60)# Cache key expires in 60 seconds.defmy_string_function(arg1):return'my_value'# Calculate expiration time with a function:@caching.cache_string()defmy_string_function(arg1):return'my_value'@my_string_function.expire_indefmy_string_function_expire_in(arg1):# ... calculate seconds or a timedeltareturndatetime.now()-some_other_datetimeIncluded Value TypesThere are decorators already defined for various common datatypes.DecoratorWrapped Function Return TypeRedis Set FunctionRedis Get FunctionRedisCaching.cache_strstrsetgetRedisCaching.cache_dict_strstrhsethgetRedisCaching.cache_dictdicthsethgetallRedisCaching.cache_listlistrpushlrangeYou can see how the various datatypes are stored and fetched incacheable.py.Special DecoratorsAll decorators accept the same arguments except for the following:RedisCaching.cache_dict_strThis decorator stores a value inside a cached dictionary (a redis hash).Usage:@caching.cache_dict_string(dict_key='foo',get_cache_key=lambdaarg1:returnf'{arg1}-cache-key')defmy_nested_value(arg1):return"bar"In the above example, callingmy_nested_value('hello')results in a cached hash with keyhello-cache-keyand value{ 'foo': 'bar' }.Custom Data TypesYou can cache and retrieve any arbitrary data type as long as it can be serialized/transformed into a type that redis supports.ExamplesCache adecimal.DecimalThis example serializesDecimalobjects to strings and coerces fetched values back intoDecimalobjects.# Define a custom `CacheElement`classCacheDecimal(CacheElement[Decimal,str]):cacheable:Cacheable[str]=StringCacheable()defload(self,value:str)->Decimal:returnDecimal(value)defdump(self,value:Decimal)->str:returnstr(value)# Use the custom CacheElement with RedisCaching.cache_value@caching.cache_value(CacheDecimal())defmy_decimal_function(arg1):returnDecimal('1.234')Cache your own serializable typeIf you have a custom data type that is serializable, you can define a customCacheElementto cache it.classMyObject:defserialize(self):# return a string representation@classmethoddeffrom_str(cls,value):# parse value and return a new instanceclassCacheMyObject(CacheElement[MyObject,str]):cacheable:Cacheable[str]=StringCacheable()defload(self,value:str)->MyObject:returnDecimal.from_str(value)defdump(self,value:MyObject)->str:returnvalue.serialize()# Use the custom CacheElement with RedisCaching.cache_value@caching.cache_value(CacheMyObject())defmy_decimal_function(arg1):returnMyObject()Note the underlyingCacheablein these examples isStringCacheable. If you want to store your object as a different type,
you can use otherCacheableclasses to do so. For example, to store your object as a dictionary, you would
use theDictCacheableinstead ofStringCacheable. WithDictCacheable, theloadfunction would take
adictobject as thevalueargument and return your object type; thedumpfunction would take your
object type as thevalueargument and return adict.Seecacheable.pyandcache_element.pyfor examples ofCacheableandCacheElement, respectively.Advanced UsageDeferred InitIf your redis config is not available at the timeRedisCachingis initialized, you can defer initialization usingRedisCaching.init.
This use case is common when using web frameworks like Flask or Pyramid, where you may have modules that use cache decorators that get
imported before your app configuration is initialized.You can create aRedisCachinginstance without providing a URL or redis config and use decorators throughout your code base. The cache functions
will get registered before the connection to redis is made.ExampleCreate an instance ofRedisCachingin, for instance,extensions.py:fromredis_decoratorsimportRedisCachingcaching=RedisCaching()Use the cache decorators wherever you need to:fromextensionsimportcaching@caching.cache_string()defmy_cached_string_function():# ...Initialize yourRedisCachinginstance after your config has been initialized:fromextensionsimportcachingdefapp():# initialize app and config, visit view modules, etc.caching.init(app.config.REDIS_URL,**app.config.REDIS_CONFIG)DevelopmentInstall dev dependenciespipinstall-rrequirements.txtRun tests with pytestpytestRun tests with a live redis serverBy default, tests are run usingfakeredisinstead of connecting to a real redis server. To run tests agains a live (local) redis server:dockercomposeup-d
pytest--redis-urlredis://localhost:6379ContributingPRs and issues are always welcome.