<s> """<STR_LIT>""" <EOL> import time <EOL> import portalocker <EOL> import shelve <EOL> import thread <EOL> import os <EOL> import logging <EOL> import re <EOL> import hashlib <EOL> import datetime <EOL> try : <EOL> from gluon import settings <EOL> have_settings = True <EOL> except ImportError : <EOL> have_settings = False <EOL> logger = logging . getLogger ( "<STR_LIT>" ) <EOL> __all__ = [ '<STR_LIT>' , '<STR_LIT>' ] <EOL> DEFAULT_TIME_EXPIRE = <NUM_LIT> <EOL> class CacheAbstract ( object ) : <EOL> """<STR_LIT>""" <EOL> cache_stats_name = '<STR_LIT>' <EOL> def __init__ ( self , request = None ) : <EOL> """<STR_LIT>""" <EOL> raise NotImplementedError <EOL> def __call__ ( self , key , f , <EOL> time_expire = DEFAULT_TIME_EXPIRE ) : <EOL> """<STR_LIT>""" <EOL> raise NotImplementedError <EOL> def clear ( self , regex = None ) : <EOL> """<STR_LIT>""" <EOL> raise NotImplementedError <EOL> def increment ( self , key , value = <NUM_LIT:1> ) : <EOL> """<STR_LIT>""" <EOL> raise NotImplementedError <EOL> def _clear ( self , storage , regex ) : <EOL> """<STR_LIT>""" <EOL> r = re . compile ( regex ) <EOL> for ( key , value ) in storage . items ( ) : <EOL> if r . match ( str ( key ) ) : <EOL> del storage [ key ] <EOL> class CacheInRam ( CacheAbstract ) : <EOL> """<STR_LIT>""" <EOL> locker = thread . allocate_lock ( ) <EOL> meta_storage = { } <EOL> def __init__ ( self , request = None ) : <EOL> self . initialized = False <EOL> self . request = request <EOL> self . storage = { } <EOL> def initialize ( self ) : <EOL> if self . initialized : <EOL> return <EOL> else : <EOL> self . initialized = True <EOL> self . locker . acquire ( ) <EOL> request = self . request <EOL> if request : <EOL> app = request . application <EOL> else : <EOL> app = '<STR_LIT>' <EOL> if not app in self . meta_storage : <EOL> self . storage = self . meta_storage [ app ] = { <EOL> CacheAbstract . cache_stats_name : { '<STR_LIT>' : <NUM_LIT:0> , '<STR_LIT>' : <NUM_LIT:0> } } <EOL> else : <EOL> self . storage = self . meta_storage [ app ] <EOL> self . locker . release ( ) <EOL> def clear ( self , regex = None ) : <EOL> self . initialize ( ) <EOL> self . locker . acquire ( ) <EOL> storage = self . storage <EOL> if regex is None : <EOL> storage . clear ( ) <EOL> else : <EOL> self . _clear ( storage , regex ) <EOL> if not CacheAbstract . cache_stats_name in storage . keys ( ) : <EOL> storage [ CacheAbstract . cache_stats_name ] = { <EOL> '<STR_LIT>' : <NUM_LIT:0> , '<STR_LIT>' : <NUM_LIT:0> } <EOL> self . locker . release ( ) <EOL> def __call__ ( self , key , f , <EOL> time_expire = DEFAULT_TIME_EXPIRE , <EOL> destroyer = None ) : <EOL> """<STR_LIT>""" <EOL> self . initialize ( ) <EOL> dt = time_expire <EOL> now = time . time ( ) <EOL> self . locker . acquire ( ) <EOL> item = self . storage . get ( key , None ) <EOL> if item and f is None : <EOL> del self . storage [ key ] <EOL> if destroyer : <EOL> destroyer ( item [ <NUM_LIT:1> ] ) <EOL> self . storage [ CacheAbstract . cache_stats_name ] [ '<STR_LIT>' ] += <NUM_LIT:1> <EOL> self . locker . release ( ) <EOL> if f is None : <EOL> return None <EOL> if item and ( dt is None or item [ <NUM_LIT:0> ] > now - dt ) : <EOL> return item [ <NUM_LIT:1> ] <EOL> elif item and ( item [ <NUM_LIT:0> ] < now - dt ) and destroyer : <EOL> destroyer ( item [ <NUM_LIT:1> ] ) <EOL> value = f ( ) <EOL> self . locker . acquire ( ) <EOL> self . storage [ key ] = ( now , value ) <EOL> self . storage [ CacheAbstract . cache_stats_name ] [ '<STR_LIT>' ] += <NUM_LIT:1> <EOL> self . locker . release ( ) <EOL> return value <EOL> def increment ( self , key , value = <NUM_LIT:1> ) : <EOL> self . initialize ( ) <EOL> self . locker . acquire ( ) <EOL> try : <EOL> if key in self . storage : <EOL> value = self . storage [ key ] [ <NUM_LIT:1> ] + value <EOL> self . storage [ key ] = ( time . time ( ) , value ) <EOL> except BaseException , e : <EOL> self . locker . release ( ) <EOL> raise e <EOL> self . locker . release ( ) <EOL> return value <EOL> class CacheOnDisk ( CacheAbstract ) : <EOL> """<STR_LIT>""" <EOL> def _close_shelve_and_unlock ( self ) : <EOL> try : <EOL> if self . storage : <EOL> self . storage . close ( ) <EOL> except ValueError : <EOL> pass <EOL> finally : <EOL> self . storage = None <EOL> if self . locker and self . locked : <EOL> portalocker . unlock ( self . locker ) <EOL> self . locker . close ( ) <EOL> self . locked = False <EOL> def _open_shelve_and_lock ( self ) : <EOL> """<STR_LIT>""" <EOL> storage = None <EOL> locker = None <EOL> locked = False <EOL> try : <EOL> locker = locker = open ( self . locker_name , '<STR_LIT:a>' ) <EOL> portalocker . lock ( locker , portalocker . LOCK_EX ) <EOL> locked = True <EOL> try : <EOL> storage = shelve . open ( self . shelve_name ) <EOL> except : <EOL> logger . error ( '<STR_LIT>' <EOL> % self . shelve_name ) <EOL> storage = None <EOL> if storage is None : <EOL> if os . path . exists ( self . shelve_name ) : <EOL> os . unlink ( self . shelve_name ) <EOL> storage = shelve . open ( self . shelve_name ) <EOL> if not CacheAbstract . cache_stats_name in storage . keys ( ) : <EOL> storage [ CacheAbstract . cache_stats_name ] = { <EOL> '<STR_LIT>' : <NUM_LIT:0> , '<STR_LIT>' : <NUM_LIT:0> } <EOL> storage . sync ( ) <EOL> except Exception , e : <EOL> if storage : <EOL> storage . close ( ) <EOL> storage = None <EOL> if locked : <EOL> portalocker . unlock ( locker ) <EOL> locker . close ( ) <EOL> locked = False <EOL> raise RuntimeError ( <EOL> '<STR_LIT>' % self . shelve_name ) <EOL> self . locker = locker <EOL> self . locked = locked <EOL> self . storage = storage <EOL> return storage <EOL> def __init__ ( self , request = None , folder = None ) : <EOL> self . initialized = False <EOL> self . request = request <EOL> self . folder = folder <EOL> self . storage = { } <EOL> def initialize ( self ) : <EOL> if self . initialized : <EOL> return <EOL> else : <EOL> self . initialized = True <EOL> folder = self . folder <EOL> request = self . request <EOL> folder = folder or os . path . join ( request . folder , '<STR_LIT>' ) <EOL> if not os . path . exists ( folder ) : <EOL> os . mkdir ( folder ) <EOL> self . locker_name = os . path . join ( folder , '<STR_LIT>' ) <EOL> self . shelve_name = os . path . join ( folder , '<STR_LIT>' ) <EOL> def clear ( self , regex = None ) : <EOL> self . initialize ( ) <EOL> storage = self . _open_shelve_and_lock ( ) <EOL> try : <EOL> if regex is None : <EOL> storage . clear ( ) <EOL> else : <EOL> self . _clear ( storage , regex ) <EOL> storage . sync ( ) <EOL> finally : <EOL> self . _close_shelve_and_unlock ( ) <EOL> def __call__ ( self , key , f , <EOL> time_expire = DEFAULT_TIME_EXPIRE ) : <EOL> self . initialize ( ) <EOL> dt = time_expire <EOL> storage = self . _open_shelve_and_lock ( ) <EOL> try : <EOL> item = storage . get ( key , None ) <EOL> storage [ CacheAbstract . cache_stats_name ] [ '<STR_LIT>' ] += <NUM_LIT:1> <EOL> if item and f is None : <EOL> del storage [ key ] <EOL> storage . sync ( ) <EOL> now = time . time ( ) <EOL> if f is None : <EOL> value = None <EOL> elif item and ( dt is None or item [ <NUM_LIT:0> ] > now - dt ) : <EOL> value = item [ <NUM_LIT:1> ] <EOL> else : <EOL> value = f ( ) <EOL> storage [ key ] = ( now , value ) <EOL> storage [ CacheAbstract . cache_stats_name ] [ '<STR_LIT>' ] += <NUM_LIT:1> <EOL> storage . sync ( ) <EOL> finally : <EOL> self . _close_shelve_and_unlock ( ) <EOL> return value <EOL> def increment ( self , key , value = <NUM_LIT:1> ) : <EOL> self . initialize ( ) <EOL> storage = self . _open_shelve_and_lock ( ) <EOL> try : <EOL> if key in storage : <EOL> value = storage [ key ] [ <NUM_LIT:1> ] + value <EOL> storage [ key ] = ( time . time ( ) , value ) <EOL> storage . sync ( ) <EOL> finally : <EOL> self . _close_shelve_and_unlock ( ) <EOL> return value <EOL> class CacheAction ( object ) : <EOL> def __init__ ( self , func , key , time_expire , cache , cache_model ) : <EOL> self . __name__ = func . __name__ <EOL> self . __doc__ = func . __doc__ <EOL> self . func = func <EOL> self . key = key <EOL> self . time_expire = time_expire <EOL> self . cache = cache <EOL> self . cache_model = cache_model <EOL> def __call__ ( self , * a , ** b ) : <EOL> if not self . key : <EOL> key2 = self . __name__ + '<STR_LIT::>' + repr ( a ) + '<STR_LIT::>' + repr ( b ) <EOL> else : <EOL> key2 = self . key . replace ( '<STR_LIT>' , self . __name__ ) . replace ( '<STR_LIT>' , str ( a ) ) . replace ( '<STR_LIT>' , str ( b ) ) <EOL> cache_model = self . cache_model <EOL> if not cache_model or isinstance ( cache_model , str ) : <EOL> cache_model = getattr ( self . cache , cache_model or '<STR_LIT>' ) <EOL> return cache_model ( key2 , <EOL> lambda a = a , b = b : self . func ( * a , ** b ) , <EOL> self . time_expire ) <EOL> class Cache ( object ) : <EOL> """<STR_LIT>""" <EOL> autokey = '<STR_LIT>' <EOL> def __init__ ( self , request ) : <EOL> """<STR_LIT>""" <EOL> if have_settings and settings . global_settings . web2py_runtime_gae : <EOL> from gluon . contrib . gae_memcache import MemcacheClient <EOL> self . ram = self . disk = MemcacheClient ( request ) <EOL> else : <EOL> self . ram = CacheInRam ( request ) <EOL> try : <EOL> self . disk = CacheOnDisk ( request ) <EOL> except IOError : <EOL> logger . warning ( '<STR_LIT>' ) <EOL> except AttributeError : <EOL> logger . warning ( '<STR_LIT>' ) <EOL> def action ( self , time_expire = DEFAULT_TIME_EXPIRE , cache_model = None , <EOL> prefix = None , session = False , vars = True , lang = True , <EOL> user_agent = False , public = True , valid_statuses = None , <EOL> quick = None ) : <EOL> """<STR_LIT>""" <EOL> from gluon import current <EOL> from gluon . http import HTTP <EOL> def wrap ( func ) : <EOL> def wrapped_f ( ) : <EOL> if current . request . env . request_method != '<STR_LIT:GET>' : <EOL> return func ( ) <EOL> if time_expire : <EOL> cache_control = '<STR_LIT>' % dict ( time_expire = time_expire ) <EOL> if quick : <EOL> session_ = True if '<STR_LIT:S>' in quick else False <EOL> vars_ = True if '<STR_LIT>' in quick else False <EOL> lang_ = True if '<STR_LIT:L>' in quick else False <EOL> user_agent_ = True if '<STR_LIT>' in quick else False <EOL> public_ = True if '<STR_LIT:P>' in quick else False <EOL> else : <EOL> session_ , vars_ , lang_ , user_agent_ , public_ = session , vars , lang , user_agent , public <EOL> if not session_ and public_ : <EOL> cache_control += '<STR_LIT>' <EOL> expires = ( current . request . utcnow + datetime . timedelta ( seconds = time_expire ) ) . strftime ( '<STR_LIT>' ) <EOL> else : <EOL> cache_control += '<STR_LIT>' <EOL> expires = '<STR_LIT>' <EOL> if cache_model : <EOL> cache_key = [ current . request . env . path_info , current . response . view ] <EOL> if session_ : <EOL> cache_key . append ( current . response . session_id ) <EOL> elif user_agent_ : <EOL> if user_agent_ is True : <EOL> cache_key . append ( "<STR_LIT>" % current . request . user_agent ( ) ) <EOL> else : <EOL> cache_key . append ( str ( user_agent_ . items ( ) ) ) <EOL> if vars_ : <EOL> cache_key . append ( current . request . env . query_string ) <EOL> if lang_ : <EOL> cache_key . append ( current . T . accepted_language ) <EOL> cache_key = hashlib . md5 ( '<STR_LIT>' . join ( cache_key ) ) . hexdigest ( ) <EOL> if prefix : <EOL> cache_key = prefix + cache_key <EOL> try : <EOL> rtn = cache_model ( cache_key , lambda : func ( ) , time_expire = time_expire ) <EOL> http , status = None , current . response . status <EOL> except HTTP , e : <EOL> rtn = cache_model ( cache_key , lambda : e . body , time_expire = time_expire ) <EOL> http , status = HTTP ( e . status , rtn , ** e . headers ) , e . status <EOL> else : <EOL> http = None <EOL> else : <EOL> try : <EOL> rtn = func ( ) <EOL> http , status = None , current . response . status <EOL> except HTTP , e : <EOL> status = e . status <EOL> http = HTTP ( e . status , e . body , ** e . headers ) <EOL> else : <EOL> http = None <EOL> send_headers = False <EOL> if http and isinstance ( valid_statuses , list ) : <EOL> if status in valid_statuses : <EOL> send_headers = True <EOL> elif valid_statuses is None : <EOL> if str ( status ) [ <NUM_LIT:0> ] in '<STR_LIT>' : <EOL> send_headers = True <EOL> if send_headers : <EOL> headers = { <EOL> '<STR_LIT>' : None , <EOL> '<STR_LIT>' : expires , <EOL> '<STR_LIT>' : cache_control <EOL> } <EOL> current . response . headers . update ( headers ) <EOL> if cache_model and not send_headers : <EOL> cache_model ( cache_key , None ) <EOL> if http : <EOL> if send_headers : <EOL> http . headers . update ( current . response . headers ) <EOL> raise http <EOL> return rtn <EOL> wrapped_f . __name__ = func . __name__ <EOL> wrapped_f . __doc__ = func . __doc__ <EOL> return wrapped_f <EOL> return wrap <EOL> def __call__ ( self , <EOL> key = None , <EOL> time_expire = DEFAULT_TIME_EXPIRE , <EOL> cache_model = None ) : <EOL> """<STR_LIT>""" <EOL> def tmp ( func , cache = self , cache_model = cache_model ) : <EOL> return CacheAction ( func , key , time_expire , self , cache_model ) <EOL> return tmp <EOL> @ staticmethod <EOL> def with_prefix ( cache_model , prefix ) : <EOL> """<STR_LIT>""" <EOL> return lambda key , f , time_expire = DEFAULT_TIME_EXPIRE , prefix = prefix : cache_model ( prefix + key , f , time_expire ) <EOL> def lazy_cache ( key = None , time_expire = None , cache_model = '<STR_LIT>' ) : <EOL> """<STR_LIT>""" <EOL> def decorator ( f , key = key , time_expire = time_expire , cache_model = cache_model ) : <EOL> key = key or repr ( f ) <EOL> def g ( * c , ** d ) : <EOL> from gluon import current <EOL> return current . cache ( key , time_expire , cache_model ) ( f ) ( * c , ** d ) <EOL> g . __name__ = f . __name__ <EOL> return g <EOL> return decorator </s>
