Package: cacheout
A caching library for Python.LinksProject:https://github.com/dgilland/cacheoutDocumentation:https://cacheout.readthedocs.ioPyPI:https://pypi.python.org/pypi/cacheout/Github Actions:https://github.com/dgilland/cacheout/actionsFeaturesIn-memory caching using dictionary backendCache manager for easily accessing multiple cache objectsReconfigurable cache settings for runtime setup when using module-level cache objectsMaximum cache size enforcementDefault cache TTL (time-to-live) as well as custom TTLs per cache entryBulk set, get, and delete operationsBulk get and delete operations filtered by string, regex, or functionMemoization decoratorsThread safeMultiple cache implementations:FIFO (First In, First Out)LIFO (Last In, First Out)LRU (Least Recently Used)MRU (Most Recently Used)LFU (Least Frequently Used)RR (Random Replacement)RoadmapLayered caching (multi-level caching)RequirementsPython >= 3.7QuickstartInstall using pip:pip install cacheoutLet’s start with some basic caching by creating a cache object:fromcacheoutimportCachecache=Cache()By default thecacheobject will have a maximum size of256, default TTL (time-to-live) expiration turned off, TTL timer that usestime.time(meaning TTL is in seconds), and the default for missing keys asNone. These values can be set with:cache=Cache(maxsize=256,ttl=0,timer=time.time,default=None)# defaultsSet a cache key usingcache.set():cache.set(1,'foobar')Get the value of a cache key withcache.get():assertcache.get(1)=='foobar'Get a default value when cache key isn’t set:assertcache.get(2)isNoneassertcache.get(2,default=False)isFalseassert2notincacheProvide cache values using a default callable:assert2notincacheassertcache.get(2,default=lambdakey:key)==2assertcache.get(2)==2assert2incacheProvide a global default:cache2=Cache(default=True)assertcache2.get('missing')isTrueassert'missing'notincache2cache3=Cache(default=lambdakey:key)assertcache3.get('missing')=='missing'assert'missing'incache3Set the TTL (time-to-live) expiration per entry (default TTL units are in seconds whenCache.timeris set to the defaulttime.time; otherwise, the units are determined by the custom timer function):cache.set(3,{'data':{}},ttl=1)assertcache.get(3)=={'data':{}}time.sleep(1)assertcache.get(3)isNoneMemoize a function where cache keys are generated from the called function parameters:@cache.memoize()deffunc(a,b):passProvide a TTL for the memoized function and incorporate argument types into generated cache keys:@cache.memoize(ttl=5,typed=True)deffunc(a,b):pass# func(1, 2) has different cache key than func(1.0, 2.0), whereas,# with "typed=False" (the default), they would have the same keyAccess the original memoized function:@cache.memoize()deffunc(a,b):passfunc.uncached(1,2)Get a copy of the entire cache withcache.copy():assertcache.copy()=={1:'foobar',2:('foo','bar','baz')}Delete a cache key withcache.delete():cache.delete(1)assertcache.get(1)isNoneClear the entire cache withcache.clear():cache.clear()assertlen(cache)==0Perform bulk operations withcache.set_many(),cache.get_many(), andcache.delete_many():cache.set_many({'a':1,'b':2,'c':3})assertcache.get_many(['a','b','c'])=={'a':1,'b':2,'c':3}cache.delete_many(['a','b','c'])assertcache.count()==0Use complex filtering incache.get_many()andcache.delete_many():importrecache.set_many({'a_1':1,'a_2':2,'123':3,'b':4})cache.get_many('a_*')=={'a_1':1,'a_2':2}cache.get_many(re.compile(r'\d'))=={'123':3}cache.get_many(lambdakey:'2'inkey)=={'a_2':2,'123':3}cache.delete_many('a_*')assertdict(cache.items())=={'123':3,'b':4}Reconfigure the cache object after creation withcache.configure():cache.configure(maxsize=1000,ttl=5*60)Get keys, values, and items from the cache withcache.keys(),cache.values(), andcache.items():cache.set_many({'a':1,'b':2,'c':3})assertlist(cache.keys())==['a','b','c']assertlist(cache.values())==[1,2,3]assertlist(cache.items())==[('a',1),('b',2),('c',3)]Iterate over cache keys:forkeyincache:print(key,cache.get(key))# 'a' 1# 'b' 2# 'c' 3Check if key exists withcache.has()andkey in cache:assertcache.has('a')assert'a'incacheUse callbacks to be notified of on-get, on-set, and on-delete events:defon_get(key,value,exists):passdefon_set(key,new_value,old_value):passdefon_delete(key,value,cause):passEnable cache statistics:cache_with_stats=Cache(enable_stats=True)# Or via configure()cache.configure(enable_stats=True)# Or directly via Cache.statscache.stats.enable()Get cache statistics:print(cache.stats.info())Manage tracking of statistics:# Pause tracking (collected stats will not be affected)cache.stats.pause()# Resume trackingcache.stats.resume()# Reset statscache.stats.reset()# Disable stats (WARNING: This resets stats)cache.stats.disable()# Disable via configure() (WARNING: This resets stats)cache.configure(enable_stats=False)Manage multiple caches usingCacheManager:fromcacheoutimportCacheManagercacheman=CacheManager({'a':{'maxsize':100},'b':{'maxsize':200,'ttl':900},'c':{})cacheman['a'].set('key1','value1')value=cacheman['a'].get('key')cacheman['b'].set('key2','value2')assertcacheman['b'].maxsize==200assertcacheman['b'].ttl==900cacheman['c'].set('key3','value3')cacheman.clear_all()forname,cacheincacheman:assertnameincachemanassertlen(cache)==0For more details, see the full documentation athttps://cacheout.readthedocs.io.Changelogv0.16.0 (2023-12-22)AddCache.on_getcallback hook. Thanksuncle-lv!AddCache.on_setcallback hook. Thanksuncle-lv!v0.15.0 (2023-11-03)Add cache statistics. Thanksuncle-lv!AddCache.get_ttl. Thanksuncle-lv!AddCache.on_deletecallback hook. Thanksuncle-lv!Add support for Python 3.11 and 3.12.v0.14.1 (2022-08-16)Set minimum Python version to 3.7 in setup.cfg.v0.14.0 (2022-08-16)Add support for Python 3.10.Drop support for Python 3.6. Minimum supported version is 3.7.Clarify docs around TTL to make it explicit what time units it uses by default.v0.13.1 (2021-04-28)Minor optimization inCache.get_many|delete_many.v0.13.0 (2021-04-27)Addcache_keyattribute to memoized functions that can be used to generate the cache key used for a given set of function arguments. Thanksjohnbergvall!Fix bug inCache.fullthat would result in an exception if cache created withmaxsize=NonelikeCache(maxsize=None). ThanksAllinolCP!Fix bug inCache.get_manythat resulted inRuntimeError: OrderedDict mutated during iterationwhen cache keys expire during theget_manycall.Removedefaultargument fromCache.get_many. A default value on missing cache key was only ever returned if a list of keys was passed in and those keys happened to expire during theget_manycall.breaking changev0.12.1 (2021-04-19)Fix regression in0.12.0that resulted in missing docstrings for some methods ofLFUCacheandLRUCache.v0.12.0 (2021-04-19)Fix bug inCache.__contains__where it would returnTruefor an expired key.Add type annotations.Add official support for Python 3.8 and 3.9.Drop support for Python 3.4 and 3.5.v0.11.2 (2019-09-30)Fix bug inLFUCachethat would result cache growing beyondmaxsizelimit.v0.11.1 (2019-01-09)Fix issue with asyncio support in memoization decorators that caused aRuntimeError: await wasn't used with futurewhen certain types of async functions were used inside the memoized function.v0.11.0 (2018-10-19)Add asyncio support to memoization decorators so they can decorate coroutines.v0.10.3 (2018-08-01)Exposetypedargument of underlying*Cache.memoize()inmemoize()and*_memoize()decorators.v0.10.2 (2018-07-31)Fix bug inLRUCache.get()where supplying adefaultvalue would result in aKeyError.v0.10.1 (2018-07-15)Support Python 3.7.v0.10.0 (2018-04-03)Modify behavior ofdefaultargument toCache.get()so that ifdefaultis a callable and the cache key is missing, then it will be called and its return value will be used as the value for cache key and subsequently be set as the value for the key in the cache. (breaking change)Adddefaultargument toCache()that can be used to override the value fordefaultinCache.get().v0.9.0 (2018-03-31)Merge functionality ofCache.get_many_by()intoCache.get_many()and removeCache.get_many_by(). (breaking change).Merge functionality ofCache.delete_many_by()intoCache.delete_many()and removeCache.delete_many_by(). (breaking change).v0.8.0 (2018-03-30)AddCache.get_many_by().AddCache.delete_many_by().MakeCache.keys()andCache.values()return dictionary view objects instead of yielding items. (breaking change)v0.7.0 (2018-02-22)Changed default cachemaxsizefrom300to256. (breaking change)AddCache.memoize()decorator.Add standalone memoization decorators:memoizefifo_memoizelfu_memoizelifo_memoizelru_memoizemru_memoizerr_memoizev0.6.0 (2018-02-05)AddLIFOCacheAddFIFOCacheas an alias ofCache.v0.5.0 (2018-02-04)AddLFUCacheDelete expired items before popping an item inCache.popitem().v0.4.0 (2018-02-02)AddMRUCacheAddRRCacheAddCache.popitem().RenameCache.expirations()toCache.expire_times(). (breaking change)RenameCache.count()toCache.size(). (breaking change)Removeminimumarguement fromCache.evict(). (breaking change)v0.3.0 (2018-01-31)AddLRUCache.AddCacheManager.__repr__().Make threading lock usage inCachemore fine-grained and eliminate redundant locking.Fix missing thread-safety inCache.__len__()andCache.__contains__().v0.2.0 (2018-01-30)RenameCache.setup()toCache.configure(). (breaking change)AddCacheManagerclass.v0.1.0 (2018-01-28)AddCacheclass.MIT LicenseCopyright (c) 2020 Derrick GillandPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.