from gluon import current
import hashlib
def newcache(time_expire, cache_model=None, session=False, vars=True, lang=False, user_agent=False, public=True):
"""
time_expire: same as @cache
cache_model: same as @cache
session: adds response.session_id to the key
vars: adds request.env.query_string
lang: adds T.accepted_language
user_agent: adds user_agent() if session is not True
public: if False forces the Cache-Control to be 'private'
"""
def wrap(f):
def wrapped_f(*args):
if current.request.env.request_method == 'GET':
if time_expire:
cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire)
if not session and public:
cache_control += ', public'
else:
cache_control += ', private'
current.response.headers['Pragma'] = None
current.response.headers['Expires'] = None
current.response.headers['Cache-Control'] = cache_control
if cache_model:
cache_key = [current.request.env.path_info, current.response.view]
if session:
cache_key.append(current.response.session_id)
elif user_agent:
cache_key.append(str(current.request.user_agent().items()))
if vars:
cache_key.append(current.request.env.query_string)
if lang:
cache_key.append(current.T.accepted_language)
cache_key = hashlib.md5('__'.join(cache_key)).hexdigest()
return cache_model(cache_key, lambda: f(), time_expire=time_expire)
return f()
return wrapped_f
return wrap
def newcache(time_expire, cache_model=None, base_key=DEFAULT, session=False, vars=True, lang=False, user_agent=False, public=True):
...
cache_key = [current.request.env.path_info, current.response.view] if base_key == DEFAULT else base_key
session = True if 'V' in quick else False
if current.request.env.request_method == 'GET':
def newcache(time_expire, cache_model=None, base_key=None, session=False, vars=True, lang=True, user_agent=False, public=True, quick=None):
"""
time_expire: same as @cache
cache_model: same as @cache
base_key: use this key and nothing else (there's cache.with_prefix for namespacing)
session: adds response.session_id to the key
vars: adds request.env.query_string
lang: adds T.accepted_language
user_agent: if True, adds is_mobile and is_tablet to the key.
Pass a dict to use all the needed values (uses str(.items())) (e.g. user_agent=request.user_agent())
used only if session is not True
public: if False forces the Cache-Control to be 'private'
quick: Session,Vars,Lang,User-agent,Public : fast overrides with initial strings, e.g. 'SVLP' or 'VLP'
"""
def wrap(f):
def wrapped_f():
if current.request.env.request_method == 'GET':
if time_expire:
cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire)
if quick:
session_ = True if 'S' in quick else False
vars_ = True if 'V' in quick else False
lang_ = True if 'L' in quick else False
user_agent_ = True if 'U' in quick else False
public_ = True if 'P' in quick else False
else:
session_, vars_, lang_, user_agent_, public_ = session, vars, lang, user_agent, public
if not session_ and public_:
cache_control += ', public'
else:
cache_control += ', private'
current.response.headers['Pragma'] = None
current.response.headers['Expires'] = None
current.response.headers['Cache-Control'] = cache_control
if cache_model:
if base_key:
cache_key = base_key
else:
cache_key = [current.request.env.path_info, current.response.view]
if session_:
cache_key.append(current.response.session_id)
elif user_agent_:
if user_agent_ is True:
cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent())
else:
cache_key.append(str(user_agent_.items()))
if vars_:
cache_key.append(current.request.env.query_string)
if lang_:
cache_key.append(current.T.accepted_language)
cache_key = hashlib.md5('__'.join(cache_key)).hexdigest()
return cache_model(cache_key, lambda: f(), time_expire=time_expire)
return f()
wrapped_f.__name__ = f.__name__
wrapped_f.__doc__ = f.__doc__
return wrapped_f
return wrap
def newcache(time_expire, cache_model=None, base_key=None, session=False, vars=True, lang=True, user_agent=False, public=True, quick=None):
"""
time_expire: same as @cache
cache_model: same as @cache
base_key: optionally replaces the default key (request.env.path_info, request.view)
cache_key = [current.request.env.path_info, current.response.view] if not base_key else [base_key]
if session_:
cache_key.append(current.response.session_id)
elif user_agent_:
if user_agent_ is True:
cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent())
else:
cache_key.append(str(user_agent_.items()))
if vars_:
cache_key.append(current.request.env.query_string)
if lang_:
cache_key.append(current.T.accepted_language)
cache_key = hashlib.md5('__'.join(cache_key)).hexdigest()
return cache_model(cache_key, lambda: f(), time_expire=time_expire)
return f()
wrapped_f.__name__ = f.__name__
wrapped_f.__doc__ = f.__doc__
return wrapped_f
return wrap
ok.
def newcache(time_expire, cache_model=None, base_key=None, session=False, vars=True, lang=True, user_agent=False, public=True, quick=None):
"""
time_expire: same as @cache
cache_model: same as @cache
base_key: optionally replaces the default key (request.env.path_info, request.view)
cache_key = [current.request.env.path_info, current.response.view] if not base_key else base_key
if session_:
cache_key.append(current.response.session_id)
elif user_agent_:
if user_agent_ is True:
cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent())
else:
cache_key.append(str(user_agent_.items()))
if vars_:
cache_key.append(current.request.env.query_string)
if lang_:
cache_key.append(current.T.accepted_language)
cache_key = hashlib.md5('__'.join(cache_key)).hexdigest()
return cache_model(cache_key, lambda: f(), time_expire=time_expire)
return f()
wrapped_f.__name__ = f.__name__
wrapped_f.__doc__ = f.__doc__
return wrapped_f
return wrap
On Tuesday, March 5, 2013 10:58:07 PM UTC+1, Anthony wrote:
base_key was intended to replace only the request.env.path_info and response.view portion of the cache_key -- even when base_key is specified, it should still be possible to optionally included session, user agent, etc.Anthony
When done please send it as apatch.
if 'client' in cache_type and time_expire:
...
if 'server' in cache_type and cache_model:
...
To do client-only caching, you would then have to do cache_type='client' rather than cache_model=None.
Another option might be to let cache_model=None default to cache.ram (as it currently does), but let cache_model=False (or maybe even cache_model='client') turn off server caching and only set the client headers.
If that's not desirable, then perhaps we can come up with a better name than newcache for this new decorator (maybe something like cscache for "client-server cache"). I would lean toward adapting the current @cache decorator if possible, though.
Anthony
The whole point was "patching" the current cache decorator to cache only GETs (including vars by default, language and user-agent) with the added bonus of being able to set without hassles the pertinent headers.
well, the implementation varies a little bit from mine to yours ....I added the prefix just as a facility because I could have used it some times (just to allow a rapid "cache.clear('prefix.*')").
On the other side, I'd never use the base_key argument if given the chance to have a prefix.... base_key in your implementation would render the same representation given different urls, that is not something I envisioned. Can you provide an example of that being useful ?
Another difference is that this works ok only for decorated functions in web2py (and decorated services). Don't know if the decorator is supposed to work also in modules.....
--
-- mail from:GoogleGroups "web2py-developers" mailing list
make speech: web2py-d...@googlegroups.com
unsubscribe: web2py-develop...@googlegroups.com
details : http://groups.google.com/group/web2py-developers
the project: http://code.google.com/p/web2py/
official : http://www.web2py.com/
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-developers" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py-developers/Jwf7WVByqLw/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to web2py-develop...@googlegroups.com.
--
-- mail from:GoogleGroups "web2py-developers" mailing list
make speech: web2py-d...@googlegroups.com
unsubscribe: web2py-develop...@googlegroups.com
details : http://groups.google.com/group/web2py-developers
the project: http://code.google.com/p/web2py/
official : http://www.web2py.com/
---
You received this message because you are subscribed to the Google Groups "web2py-developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py-develop...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
<newcache_decorator.py>
Maybe I'm not following correctly -- if the function generates an error, won't it occur (and response.status get changed to an error code) after you check for a valid response.status?
def whatever():
try:
rtn = sometimes_fails()
except:
rtn = 'try again in a few minutes'
response.status = 503
return rtn
Also, are you no longer providing a client-only option (looks like headers are only set when cache_model is specified)?