misiing </a> in template reported by Mike G
[pyTivo/wmcbrine/lucasnz.git] / Cheetah / CacheRegion.py
blob89daf9d78e39c5581c1030d8b6cb8244dac97f87
1 # $Id: CacheRegion.py,v 1.3 2006/01/28 04:19:30 tavis_rudd Exp $
2 """Cache holder classes for Cheetah:
4 Cache regions are defined using the #cache Cheetah directive. Each
5 cache region can be viewed as a dictionary (keyed by cacheRegionID)
6 handling at least one cache item (the default one). It's possible to add
7 cacheItems in a region by using the `varyBy` #cache directive parameter as
8 in the following example::
9 #def getArticle
10 this is the article content.
11 #end def
13 #cache varyBy=$getArticleID()
14 $getArticle($getArticleID())
15 #end cache
17 The code above will generate a CacheRegion and add new cacheItem for each value
18 of $getArticleID().
20 Meta-Data
21 ================================================================================
22 Author: Tavis Rudd <tavis@damnsimple.com> and Philippe Normand <phil@base-art.net>
23 Version: $Revision: 1.3 $
24 Start Date: 2005/06/20
25 Last Revision Date: $Date: 2006/01/28 04:19:30 $
26 """
27 __author__ = "Tavis Rudd <tavis@damnsimple.com> and Philippe Normand <phil@base-art.net>"
28 __revision__ = "$Revision: 1.3 $"[11:-2]
30 try:
31 import hashlib
32 except:
33 import md5 as hashlib
34 from time import time as currentTime
35 from Cheetah.CacheStore import MemoryCacheStore
37 class CacheItem:
38 """A CacheItem is a container storing:
40 - cacheID (string)
41 - refreshTime (timestamp or None) : last time the cache was refreshed
42 - data (string) : the content of the cache
43 """
45 def __init__(self, cacheItemID, cacheStore):
46 self._cacheItemID = cacheItemID
47 self._cacheStore = cacheStore
48 self._refreshTime = None
49 self._expiryTime = 0
51 def hasExpired(self):
52 return (self._expiryTime and currentTime() > self._expiryTime)
54 def setExpiryTime(self, time):
55 self._expiryTime = time
57 def getExpiryTime(self):
58 return self._expiryTime
60 def setData(self, data):
61 self._refreshTime = currentTime()
62 self._cacheStore.set(self._cacheItemID, data, self._expiryTime)
64 def getRefreshTime(self):
65 return self._refreshTime
67 def getData(self):
68 assert self._refreshTime
69 return self._cacheStore.get(self._cacheItemID)
71 def renderOutput(self):
72 """Can be overridden to implement edge-caching"""
73 return self.getData() or ""
75 def clear(self):
76 self._cacheStore.delete(self._cacheItemID)
77 self._refreshTime = None
79 class _CacheDataStoreWrapper:
80 def __init__(self, dataStore, keyPrefix):
81 self._dataStore = dataStore
82 self._keyPrefix = keyPrefix
84 def get(self, key):
85 return self._dataStore.get(self._keyPrefix+key)
87 def delete(self, key):
88 self._dataStore.delete(self._keyPrefix+key)
90 def set(self, key, val, time=0):
91 self._dataStore.set(self._keyPrefix+key, val, time=time)
93 class CacheRegion:
94 """ A `CacheRegion` stores some `CacheItem` instances.
96 This implementation stores the data in the memory of the current process.
97 If you need a more advanced data store, create a cacheStore class that works
98 with Cheetah's CacheStore protocol and provide it as the cacheStore argument
99 to __init__. For example you could use
100 Cheetah.CacheStore.MemcachedCacheStore, a wrapper around the Python
101 memcached API (http://www.danga.com/memcached).
103 _cacheItemClass = CacheItem
105 def __init__(self, regionID, templateCacheIdPrefix='', cacheStore=None):
106 self._isNew = True
107 self._regionID = regionID
108 self._templateCacheIdPrefix = templateCacheIdPrefix
109 if not cacheStore:
110 cacheStore = MemoryCacheStore()
111 self._cacheStore = cacheStore
112 self._wrappedCacheDataStore = _CacheDataStoreWrapper(
113 cacheStore, keyPrefix=templateCacheIdPrefix+':'+regionID+':')
114 self._cacheItems = {}
116 def isNew(self):
117 return self._isNew
119 def clear(self):
120 " drop all the caches stored in this cache region "
121 for cacheItemId in self._cacheItems.keys():
122 cacheItem = self._cacheItems[cacheItemId]
123 cacheItem.clear()
124 del self._cacheItems[cacheItemId]
126 def getCacheItem(self, cacheItemID):
127 """ Lazy access to a cacheItem
129 Try to find a cache in the stored caches. If it doesn't
130 exist, it's created.
132 Returns a `CacheItem` instance.
134 cacheItemID = hashlib.md5(str(cacheItemID)).hexdigest()
136 if not self._cacheItems.has_key(cacheItemID):
137 cacheItem = self._cacheItemClass(
138 cacheItemID=cacheItemID, cacheStore=self._wrappedCacheDataStore)
139 self._cacheItems[cacheItemID] = cacheItem
140 self._isNew = False
141 return self._cacheItems[cacheItemID]