David Beitey avatar David Beitey committed 7555c6a

Add ability for expiration_time passed to cache_on_arguments to be dynamic (eg
callable called when decorated function is called)

Comments (0)

Files changed (2)

dogpile/cache/region.py

          being declared.
         :param expiration_time: if not None, will override the normal
          expiration time.
+        
+         May be specified as a callable, taking no arguments, that
+         returns a value to be used as the ``expiration_time``. This callable
+         will be called whenever the decorated function itself is called, in
+         caching or retrieving. Thus, this can be used to
+         determine a *dynamic* expiration time for the cached function
+         result.  Example use cases include "cache the result until the
+         end of the day, week or time period" and "cache until a certain date
+         or time passes".
         :param should_cache_fn: passed to :meth:`.CacheRegion.get_or_create`.
 
           .. versionadded:: 0.4.3
 
         """
+        expiration_time_is_callable = callable(expiration_time)
         def decorator(fn):
             key_generator = self.function_key_generator(namespace, fn)
             @wraps(fn)
                 @wraps(fn)
                 def creator():
                     return fn(*arg, **kw)
-                return self.get_or_create(key, creator, expiration_time,
-                                                should_cache_fn)
-
+                timeout = expiration_time_is_callable and \
+                        expiration_time() or expiration_time
+                return self.get_or_create(key, creator, timeout,
+                                          should_cache_fn)
 
             def invalidate(*arg, **kw):
                 key = key_generator(*arg, **kw)

tests/cache/test_decorator.py

         time.sleep(.3)
         eq_(go(1, 2), (3, 1, 2))
 
+    def test_decorator_expire_callable(self):
+        go = self._fixture(expiration_time=lambda: .5)
+        eq_(go(1, 2), (1, 1, 2))
+        eq_(go(3, 4), (2, 3, 4))
+        eq_(go(1, 2), (1, 1, 2))
+        time.sleep(.3)
+        eq_(go(1, 2), (1, 1, 2))
+        time.sleep(.3)
+        eq_(go(1, 2), (3, 1, 2))
+
     def test_explicit_expire(self):
         go = self._fixture(expiration_time=1)
         eq_(go(1, 2), (1, 1, 2))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.