Package: gocept.cache
Contentsgocept.cacheMethod cacheMemoize with timeoutExplicitly exclude caching of a certain valueStore memoizations on an attributeCached PropertiesChanges5.0 (2021-08-31)Backwards incompatible changesFeaturesOther changes4.0 (2020-02-17)3.1 (2018-11-20)3.0 (2017-11-20)2.1 (2016-11-17)2.0 (2016-03-18)1.0 (2015-09-25)0.6.1 (2013-09-13)0.6 (2013-09-13)0.6b2 (2013-09-05)0.6b1 (2013-09-05)0.5.2 (2012-06-22)0.5.1 (2012-03-10)0.5 (2011-03-15)0.4 (2009-06-18)0.3 (2008-12-19)0.2.2 (2007-12-17)0.2.1 (2007-10-17)gocept.cacheMethod cacheMemoize with timeoutMemoize with timeout caches methods with a certain timeout:>>> import math
>>> import gocept.cache.method
>>>
>>> class Point(object):
...
...     def __init__(self, x, y):
...         self.x, self.y = x, y
...
...     @gocept.cache.method.Memoize(0.1)
...     def distance(self, x, y):
...         print('computing distance')
...         return math.sqrt((self.x - x)**2 + (self.y - y)**2)
...
...     @gocept.cache.method.Memoize(0.1, ignore_self=True)
...     def add_one(self, i):
...         if not isinstance(i, int):
...             print("I want an int")
...         else:
...             print('adding one')
...             return i + 1
...
>>> point = Point(1.0, 2.0)When we first ask for the distance it is computed:>>> point.distance(2, 2)
computing distance
1.0The second time the distance is not computed but returned from the cache:>>> point.distance(2, 2)
1.0Now, let’s wait 0.1 secondes, the value we set as cache timeout. After that the
distance is computed again:>>> import time
>>> time.sleep(0.5)
>>> point.distance(2, 2)
computing distance
1.0When we create a new instance, the new instance gets its own cache:>>> p2 = Point(1.0, 2.0)
>>> p2.distance(2, 2)
computing distance
1.0It’s also possible to explicitly ignore self. We did this for theadd_onemethod:>>> point.add_one(3)
adding one
4The second time it’s not computed as you would expect:
>>> point.add_one(3)
4If we askp2now the result is not computed as well:>>> p2.add_one(3)
4If we put a non hashable argument into a memoized function it will not be
cached:>>> point.add_one({'a': 1})
I want an int
>>> point.add_one({'a': 1})
I want an intThe decorated method can be inspected and yields the same results as the
original:>>> from inspect import signature
>>> Point.distance.__name__
'distance'
>>> tuple(signature(Point.distance).parameters.keys())
('self', 'x', 'y')Explicitly exclude caching of a certain valueEspecially when talking to external systems, you want to handle
errors (i.e. by returning an emtpy result). But normally you
do not want to cache this special return value.This is our database.>>> class DB(object):
...
...     call_count = 0
...
...     def get_country(self, zip):
...         self.call_count += 1
...         if self.call_count % 2 == 0:
...             raise ValueError('Some strange response')
...         return 'Somecountry'
...It will throw an exception with every 2nd call:>>> db = DB()
>>> db.get_country(12345)
'Somecountry'>>> db.get_country(12345)
Traceback (most recent call last):
...
ValueError: Some strange response>>> db.get_country(12345)
'Somecountry'>>> db.get_country(12345)
Traceback (most recent call last):
...
ValueError: Some strange responseNow we use do_not_cache_and_return to specify that we do
not want to cache if there was en error.>>> import gocept.cache.method
>>>
>>> class Country(object):
...
...     db = DB()
...
...     @gocept.cache.method.Memoize(1000)
...     def by_zip(self, zip):
...         try:
...             return self.db.get_country(zip)
...         except ValueError:
...             return gocept.cache.method.do_not_cache_and_return(
...                     'DB is down.')
...>>> country = Country()First call will get cached, so we get the correct country with every call:>>> country.by_zip(12345)
'Somecountry'>>> country.by_zip(12345)
'Somecountry'>>> country.by_zip(12345)
'Somecountry'By using a new zip, the get_country method is called the second time, and
there will be an exception, which is not cached:>>> country.by_zip(54321)
'DB is down.'Calling it again will call get_country, because special return value is not
cached:>>> country.by_zip(54321)
'Somecountry'Now we always get the cached value:>>> country.by_zip(54321)
'Somecountry'Store memoizations on an attributeIf you want more control over the cache used by gocept.cache.method.Memoize
(e. g. you want to associate it with a gocept.cache.property.CacheDataManager
to invalidate it on transaction boundaries), you can use the @memoize_on_attribute
decorator to retrieve the cache-dictionary from the instance:>>> class Bar(object):
...     cache = {}
...
...     @gocept.cache.method.memoize_on_attribute('cache', 10)
...     def echo(self, x):
...         print('miss')
...         return x>>> bar = Bar()
>>> bar.echo(5)
miss
5
>>> bar.echo(5)
5
>>> bar.cache.clear()
>>> bar.echo(5)
miss
5This decorator should be used on methods, not on plain functions, since it must
be able to retrieve the cache-dictionary from the first argument of the function
(which is ‘self’ for methods):>>> @gocept.cache.method.memoize_on_attribute('cache', 10)
... def bar():
...     print('foo')
>>> bar()
Traceback (most recent call last):
TypeError: gocept.cache.method.memoize_on_attribute could not retrieve cache attribute 'cache' for function <function bar at 0x...>>>> @gocept.cache.method.memoize_on_attribute('cache', 10)
... def baz(x):
...     print('foo')
>>> baz(5)
Traceback (most recent call last):
TypeError: gocept.cache.method.memoize_on_attribute could not retrieve cache attribute 'cache' for function <function baz at 0x...>Cached PropertiesTransaction Bound CacheThe transaction bound cache is invalidated on transaction boundaries.Create a class and set some data:>>> import gocept.cache.property
>>> class Foo(object):
...
...     cache = gocept.cache.property.TransactionBoundCache('_v_cache', dict)
...(NOTE: You probably want to use a “volatile” attribute name for the cache
storage, otherwise a read-only access of the cache triggers a write.)>>> foo = Foo()
>>> foo.cache
{}
>>> foo.cache['A'] = 1
>>> foo.cache
{'A': 1}If we commit the transaction the cache is empty again:>>> import transaction
>>> transaction.commit()
>>> foo.cache
{}The same happens on abort:>>> foo.cache['A'] = 1
>>> foo.cache
{'A': 1}
>>> transaction.abort()
>>> foo.cache
{}Changes5.0 (2021-08-31)Backwards incompatible changesChange license from ZPL to MIT.Drop support for Python 2.7 and 3.6.FeaturesAdd support for Python 3.10.Other changesUse Github actions as CI.4.0 (2020-02-17)Add support for Python 3.7, 3.8 and 3.9a3.Drop support for Python 3.4 and 3.5.Migrate to github.3.1 (2018-11-20)Add support for Python 3.7.Remove DeprecationWarnings concerning inspect.3.0 (2017-11-20)Remove use of__file__in setup.py, to accommodate recent setuptools.Add support for Python 3.6.Drop support for Python 3.3.2.1 (2016-11-17)Bugfix:.property.CacheDataManagerno longer invalidates the cache intpc_vote()andcommit()but intpc_finish().RaiseTransactionJoinErrorif joining the transaction failed in.property.TransactionBoundCache.2.0 (2016-03-18)Drop support of Python 2.6.Declare support of PyPy and PyPy3.1.0 (2015-09-25)Now testing against currently newest versions of dependencies.Drop support of Python 3.2.Declare Support of Python 3.4 and 3.5.0.6.1 (2013-09-13)Finish Python 3 compatibility0.6 (2013-09-13)Changes not recored, sorry.0.6b2 (2013-09-05)Changes not recored, sorry.0.6b1 (2013-09-05)Python3 compatibility0.5.2 (2012-06-22)Addedgocept.cache.method.do_not_cache_and_return(value)in memoized
methods/functions which will return the given value, without caching it.0.5.1 (2012-03-10)Prevent race condition which caused values ofgocept.cache.method.Memoizenot to be stored when collect was called during the Memoize call
(in multi threaded environments).Pin test versions to ZTK 1.10.5 (2011-03-15)Replace dependency on ZODB with a dependency on transaction.0.4 (2009-06-18)Registered clearing the cache with zope.testing.cleanup.0.3 (2008-12-19)Added @memoize_on_attribute to retrieve the memoization cache from the
instance instead of using gocept.cache.method’s built-in cache.0.2.2 (2007-12-17)Fixed the bug inTransactionBoundCachewhere the cache was not invalidated
on transaction abort.0.2.1 (2007-10-17)Fixed a bug inTransactionBoundCachewhich yielded an error in the log:TypeError: <lambda>() takes exactly 1 argument (2 given)