Package pyperry :: Package middlewares :: Module local_cache
[frames] | no frames]

Source Code for Module pyperry.middlewares.local_cache

  1  from datetime import datetime, timedelta 
  2  import hashlib 
  3   
  4  from pyperry.relation import Relation 
  5   
6 -class CacheStore(object):
7
8 - def __init__(self, interval):
9 self.default_interval = timedelta(seconds=interval) 10 self.store = {}
11
12 - def read(self, key):
13 if self.store.has_key(key): 14 if self.store[key][1] > datetime.now(): 15 return self.store[key][0] 16 else: 17 del self.store[key]
18
19 - def write(self, key, val, expire_at=None):
20 self.clear() 21 self.store[key] = (val, 22 expire_at or (datetime.now() + self.default_interval))
23
24 - def clear(self, key=None):
25 if key: 26 del self.store[key] 27 else: 28 now = datetime.now() 29 for key in self.store.keys(): 30 if self.store[key][1] < now: 31 del self.store[key]
32
33 - def empty(self):
34 del self.store 35 self.store = {}
36 37
38 -class LocalCache(object):
39 """ LocalCache middleware 40 41 Caches results of queries in memory returning the previous result of 42 repeated queries until the entry expires. Entries are cached based on 43 the query used. 44 45 Config options: 46 - interval: The interval in seconds that a given cache entry will be 47 considered fresh 48 - max_entry_size: Max len of results that will be cached. If set only 49 results less than this value will be stored in the cache. All others 50 will be refetched every time. 51 52 Importing this module adds the fresh query option to Relation. This allows 53 the developer to easily force a query to be fresh:: 54 55 # This query will always fetch fresh data 56 Person.where({ 'name': 'bob' }).fresh() 57 58 """ 59 # Initialize store with default interval of 5 minutes 60 cache_store = CacheStore(300) 61
62 - def __init__(self, next, options=None):
63 if not options: 64 options = {} 65 self.next = next 66 self.options = options
67
68 - def __call__(self, **kwargs):
69 rel = kwargs['relation'] 70 key = hashlib.sha1("%s--%s" % (rel.klass, rel.query())).hexdigest() 71 72 result = self.cache_store.read(key) 73 74 if not result or rel.params['fresh']: 75 # Call the next item in the stack to get a fresh result 76 result = self.next(**kwargs) 77 78 # Use configured cache expiry interval if set 79 expires_at = None 80 if self.options.has_key('interval'): 81 expires_at = (datetime.now() + 82 timedelta(seconds=self.options.get('interval'))) 83 84 # Only store records < configured max_entry_size if set 85 if (not self.options.has_key('max_entry_size') or 86 self.options['max_entry_size'] > len(result)): 87 self.cache_store.write(key, result, expires_at) 88 89 return result
90 91 cache_store = LocalCache.cache_store 92 93 ## 94 # Add features to Relation needed for caching 95 # 96 if not Relation.singular_query_methods.count('fresh'): 97 Relation.singular_query_methods.append('fresh') 98
99 - def fresh(self, value=True):
100 self = self.clone() 101 self.params['fresh'] = value 102 self._query = None 103 self._records = None 104 return self
105 106 setattr(Relation, 'fresh', fresh) 107