def timed(timeout): def get_timed_key(func, *args, **kw): key = (args, frozenset(kw.items()), time.time() // timeout) return key return volatile.cache(get_timed_key, get_cache=store_in_cache_with_timeout(timeout))
def memoize(fun): def get_key(fun, *args, **kwargs): return (args, frozenset(kwargs.items()), ) def get_cache(fun, *args, **kwargs): return _memos return volatile.cache(get_key, get_cache)(fun)
def cache(get_key, get_request='request'): return volatile.cache(get_key, get_cache=store_in_annotation_of(get_request))
def cache(get_key, get_request='request'): r""" This is a hypothetical function `increment` that'll store the cache value on `a.request`, where a is the only argument to the function: >>> def increment(a): ... print 'Someone or something called me' ... return a + 1 Now we need to define this `a`. For this, we'll inherit from `int` and add a `request` class variable. Note that we also make our fake request `IAttributeAnnotatable`, because that's how the cache values are stored on the request: >>> from zope.publisher.browser import TestRequest >>> class A(int): ... request = TestRequest() >>> from zope.interface import directlyProvides >>> from zope.annotation.interfaces import IAttributeAnnotatable >>> directlyProvides(A.request, IAttributeAnnotatable) In addition to this request, we'll also need to set up a cache key generator. We'll use the integer value of the only argument for that: >>> get_key = lambda fun, a, *args: a Let's decorate our `increment` function now with the `cache` decorator. We'll tell the decorator to use `args_hash` for generating the key. `get_request` will tell the decorator how to actually find the `request` in the variable scope of the function itself: >>> cached_increment = \ ... cache(get_key=get_key, get_request='a.request')(increment) >>> cached_increment(A(1)) Someone or something called me 2 >>> cached_increment(A(1)) 2 >>> IAnnotations(A.request) {'plone.memoize.request.increment:1': 2} If `request` is already part of the function's argument list, we don't need to specify any expression: >>> @cache(get_key=get_key) ... def increment_plus(a, request): ... print 'Someone or something called me' ... return a + 1 >>> increment_plus(42, A.request) Someone or something called me 43 >>> increment_plus(42, A.request) 43 >>> IAnnotations(A.request)['plone.memoize.request.increment_plus:42'] 43 Create a function that can also take keyword arguments. For the sake of convenience pass the request explicitly. get_key must be modified to take kwargs into account: >>> def get_key(fun, a, request, **kwargs): ... li = kwargs.items() ... li.sort() ... return "%s,%s" % (a, li) >>> @cache(get_key=get_key) ... def increment_kwargs(a, request, kwarg1=1, kwarg2=2): ... print 'Someone or something called me' ... return a + 1 >>> increment_kwargs(42, A.request, kwarg1='kwarg1', kwarg2='kwarg2') Someone or something called me 43 >>> increment_kwargs(42, A.request, kwarg1='kwarg1', kwarg2='kwarg2') 43 >>> IAnnotations(A.request)["plone.memoize.request.increment_kwargs:42,[('kwarg1', 'kwarg1'), ('kwarg2', 'kwarg2')]"] 43 Call increment_kwargs without specifying any keyword arguments: >>> increment_kwargs(42, A.request) Someone or something called me 43 >>> increment_kwargs(42, A.request) 43 >>> IAnnotations(A.request)["plone.memoize.request.increment_kwargs:42,[]"] 43 Call increment_kwargs and specify only the second keyword argument: >>> increment_kwargs(42, A.request, kwarg2='kwarg2') Someone or something called me 43 >>> increment_kwargs(42, A.request, kwarg2='kwarg2') 43 >>> IAnnotations(A.request)["plone.memoize.request.increment_kwargs:42,[('kwarg2', 'kwarg2')]"] 43 """ return volatile.cache(get_key, get_cache=store_in_annotation_of(get_request))
def cache(get_key): return volatile.cache(get_key, get_cache=store_in_cache)