1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 2*635a8641SAndroid Build Coastguard Worker""" 3*635a8641SAndroid Build Coastguard Worker jinja2.bccache 4*635a8641SAndroid Build Coastguard Worker ~~~~~~~~~~~~~~ 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Worker This module implements the bytecode cache system Jinja is optionally 7*635a8641SAndroid Build Coastguard Worker using. This is useful if you have very complex template situations and 8*635a8641SAndroid Build Coastguard Worker the compiliation of all those templates slow down your application too 9*635a8641SAndroid Build Coastguard Worker much. 10*635a8641SAndroid Build Coastguard Worker 11*635a8641SAndroid Build Coastguard Worker Situations where this is useful are often forking web applications that 12*635a8641SAndroid Build Coastguard Worker are initialized on the first request. 13*635a8641SAndroid Build Coastguard Worker 14*635a8641SAndroid Build Coastguard Worker :copyright: (c) 2017 by the Jinja Team. 15*635a8641SAndroid Build Coastguard Worker :license: BSD. 16*635a8641SAndroid Build Coastguard Worker""" 17*635a8641SAndroid Build Coastguard Workerfrom os import path, listdir 18*635a8641SAndroid Build Coastguard Workerimport os 19*635a8641SAndroid Build Coastguard Workerimport sys 20*635a8641SAndroid Build Coastguard Workerimport stat 21*635a8641SAndroid Build Coastguard Workerimport errno 22*635a8641SAndroid Build Coastguard Workerimport marshal 23*635a8641SAndroid Build Coastguard Workerimport tempfile 24*635a8641SAndroid Build Coastguard Workerimport fnmatch 25*635a8641SAndroid Build Coastguard Workerfrom hashlib import sha1 26*635a8641SAndroid Build Coastguard Workerfrom jinja2.utils import open_if_exists 27*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import BytesIO, pickle, PY2, text_type 28*635a8641SAndroid Build Coastguard Worker 29*635a8641SAndroid Build Coastguard Worker 30*635a8641SAndroid Build Coastguard Worker# marshal works better on 3.x, one hack less required 31*635a8641SAndroid Build Coastguard Workerif not PY2: 32*635a8641SAndroid Build Coastguard Worker marshal_dump = marshal.dump 33*635a8641SAndroid Build Coastguard Worker marshal_load = marshal.load 34*635a8641SAndroid Build Coastguard Workerelse: 35*635a8641SAndroid Build Coastguard Worker 36*635a8641SAndroid Build Coastguard Worker def marshal_dump(code, f): 37*635a8641SAndroid Build Coastguard Worker if isinstance(f, file): 38*635a8641SAndroid Build Coastguard Worker marshal.dump(code, f) 39*635a8641SAndroid Build Coastguard Worker else: 40*635a8641SAndroid Build Coastguard Worker f.write(marshal.dumps(code)) 41*635a8641SAndroid Build Coastguard Worker 42*635a8641SAndroid Build Coastguard Worker def marshal_load(f): 43*635a8641SAndroid Build Coastguard Worker if isinstance(f, file): 44*635a8641SAndroid Build Coastguard Worker return marshal.load(f) 45*635a8641SAndroid Build Coastguard Worker return marshal.loads(f.read()) 46*635a8641SAndroid Build Coastguard Worker 47*635a8641SAndroid Build Coastguard Worker 48*635a8641SAndroid Build Coastguard Workerbc_version = 3 49*635a8641SAndroid Build Coastguard Worker 50*635a8641SAndroid Build Coastguard Worker# magic version used to only change with new jinja versions. With 2.6 51*635a8641SAndroid Build Coastguard Worker# we change this to also take Python version changes into account. The 52*635a8641SAndroid Build Coastguard Worker# reason for this is that Python tends to segfault if fed earlier bytecode 53*635a8641SAndroid Build Coastguard Worker# versions because someone thought it would be a good idea to reuse opcodes 54*635a8641SAndroid Build Coastguard Worker# or make Python incompatible with earlier versions. 55*635a8641SAndroid Build Coastguard Workerbc_magic = 'j2'.encode('ascii') + \ 56*635a8641SAndroid Build Coastguard Worker pickle.dumps(bc_version, 2) + \ 57*635a8641SAndroid Build Coastguard Worker pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1]) 58*635a8641SAndroid Build Coastguard Worker 59*635a8641SAndroid Build Coastguard Worker 60*635a8641SAndroid Build Coastguard Workerclass Bucket(object): 61*635a8641SAndroid Build Coastguard Worker """Buckets are used to store the bytecode for one template. It's created 62*635a8641SAndroid Build Coastguard Worker and initialized by the bytecode cache and passed to the loading functions. 63*635a8641SAndroid Build Coastguard Worker 64*635a8641SAndroid Build Coastguard Worker The buckets get an internal checksum from the cache assigned and use this 65*635a8641SAndroid Build Coastguard Worker to automatically reject outdated cache material. Individual bytecode 66*635a8641SAndroid Build Coastguard Worker cache subclasses don't have to care about cache invalidation. 67*635a8641SAndroid Build Coastguard Worker """ 68*635a8641SAndroid Build Coastguard Worker 69*635a8641SAndroid Build Coastguard Worker def __init__(self, environment, key, checksum): 70*635a8641SAndroid Build Coastguard Worker self.environment = environment 71*635a8641SAndroid Build Coastguard Worker self.key = key 72*635a8641SAndroid Build Coastguard Worker self.checksum = checksum 73*635a8641SAndroid Build Coastguard Worker self.reset() 74*635a8641SAndroid Build Coastguard Worker 75*635a8641SAndroid Build Coastguard Worker def reset(self): 76*635a8641SAndroid Build Coastguard Worker """Resets the bucket (unloads the bytecode).""" 77*635a8641SAndroid Build Coastguard Worker self.code = None 78*635a8641SAndroid Build Coastguard Worker 79*635a8641SAndroid Build Coastguard Worker def load_bytecode(self, f): 80*635a8641SAndroid Build Coastguard Worker """Loads bytecode from a file or file like object.""" 81*635a8641SAndroid Build Coastguard Worker # make sure the magic header is correct 82*635a8641SAndroid Build Coastguard Worker magic = f.read(len(bc_magic)) 83*635a8641SAndroid Build Coastguard Worker if magic != bc_magic: 84*635a8641SAndroid Build Coastguard Worker self.reset() 85*635a8641SAndroid Build Coastguard Worker return 86*635a8641SAndroid Build Coastguard Worker # the source code of the file changed, we need to reload 87*635a8641SAndroid Build Coastguard Worker checksum = pickle.load(f) 88*635a8641SAndroid Build Coastguard Worker if self.checksum != checksum: 89*635a8641SAndroid Build Coastguard Worker self.reset() 90*635a8641SAndroid Build Coastguard Worker return 91*635a8641SAndroid Build Coastguard Worker # if marshal_load fails then we need to reload 92*635a8641SAndroid Build Coastguard Worker try: 93*635a8641SAndroid Build Coastguard Worker self.code = marshal_load(f) 94*635a8641SAndroid Build Coastguard Worker except (EOFError, ValueError, TypeError): 95*635a8641SAndroid Build Coastguard Worker self.reset() 96*635a8641SAndroid Build Coastguard Worker return 97*635a8641SAndroid Build Coastguard Worker 98*635a8641SAndroid Build Coastguard Worker def write_bytecode(self, f): 99*635a8641SAndroid Build Coastguard Worker """Dump the bytecode into the file or file like object passed.""" 100*635a8641SAndroid Build Coastguard Worker if self.code is None: 101*635a8641SAndroid Build Coastguard Worker raise TypeError('can\'t write empty bucket') 102*635a8641SAndroid Build Coastguard Worker f.write(bc_magic) 103*635a8641SAndroid Build Coastguard Worker pickle.dump(self.checksum, f, 2) 104*635a8641SAndroid Build Coastguard Worker marshal_dump(self.code, f) 105*635a8641SAndroid Build Coastguard Worker 106*635a8641SAndroid Build Coastguard Worker def bytecode_from_string(self, string): 107*635a8641SAndroid Build Coastguard Worker """Load bytecode from a string.""" 108*635a8641SAndroid Build Coastguard Worker self.load_bytecode(BytesIO(string)) 109*635a8641SAndroid Build Coastguard Worker 110*635a8641SAndroid Build Coastguard Worker def bytecode_to_string(self): 111*635a8641SAndroid Build Coastguard Worker """Return the bytecode as string.""" 112*635a8641SAndroid Build Coastguard Worker out = BytesIO() 113*635a8641SAndroid Build Coastguard Worker self.write_bytecode(out) 114*635a8641SAndroid Build Coastguard Worker return out.getvalue() 115*635a8641SAndroid Build Coastguard Worker 116*635a8641SAndroid Build Coastguard Worker 117*635a8641SAndroid Build Coastguard Workerclass BytecodeCache(object): 118*635a8641SAndroid Build Coastguard Worker """To implement your own bytecode cache you have to subclass this class 119*635a8641SAndroid Build Coastguard Worker and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of 120*635a8641SAndroid Build Coastguard Worker these methods are passed a :class:`~jinja2.bccache.Bucket`. 121*635a8641SAndroid Build Coastguard Worker 122*635a8641SAndroid Build Coastguard Worker A very basic bytecode cache that saves the bytecode on the file system:: 123*635a8641SAndroid Build Coastguard Worker 124*635a8641SAndroid Build Coastguard Worker from os import path 125*635a8641SAndroid Build Coastguard Worker 126*635a8641SAndroid Build Coastguard Worker class MyCache(BytecodeCache): 127*635a8641SAndroid Build Coastguard Worker 128*635a8641SAndroid Build Coastguard Worker def __init__(self, directory): 129*635a8641SAndroid Build Coastguard Worker self.directory = directory 130*635a8641SAndroid Build Coastguard Worker 131*635a8641SAndroid Build Coastguard Worker def load_bytecode(self, bucket): 132*635a8641SAndroid Build Coastguard Worker filename = path.join(self.directory, bucket.key) 133*635a8641SAndroid Build Coastguard Worker if path.exists(filename): 134*635a8641SAndroid Build Coastguard Worker with open(filename, 'rb') as f: 135*635a8641SAndroid Build Coastguard Worker bucket.load_bytecode(f) 136*635a8641SAndroid Build Coastguard Worker 137*635a8641SAndroid Build Coastguard Worker def dump_bytecode(self, bucket): 138*635a8641SAndroid Build Coastguard Worker filename = path.join(self.directory, bucket.key) 139*635a8641SAndroid Build Coastguard Worker with open(filename, 'wb') as f: 140*635a8641SAndroid Build Coastguard Worker bucket.write_bytecode(f) 141*635a8641SAndroid Build Coastguard Worker 142*635a8641SAndroid Build Coastguard Worker A more advanced version of a filesystem based bytecode cache is part of 143*635a8641SAndroid Build Coastguard Worker Jinja2. 144*635a8641SAndroid Build Coastguard Worker """ 145*635a8641SAndroid Build Coastguard Worker 146*635a8641SAndroid Build Coastguard Worker def load_bytecode(self, bucket): 147*635a8641SAndroid Build Coastguard Worker """Subclasses have to override this method to load bytecode into a 148*635a8641SAndroid Build Coastguard Worker bucket. If they are not able to find code in the cache for the 149*635a8641SAndroid Build Coastguard Worker bucket, it must not do anything. 150*635a8641SAndroid Build Coastguard Worker """ 151*635a8641SAndroid Build Coastguard Worker raise NotImplementedError() 152*635a8641SAndroid Build Coastguard Worker 153*635a8641SAndroid Build Coastguard Worker def dump_bytecode(self, bucket): 154*635a8641SAndroid Build Coastguard Worker """Subclasses have to override this method to write the bytecode 155*635a8641SAndroid Build Coastguard Worker from a bucket back to the cache. If it unable to do so it must not 156*635a8641SAndroid Build Coastguard Worker fail silently but raise an exception. 157*635a8641SAndroid Build Coastguard Worker """ 158*635a8641SAndroid Build Coastguard Worker raise NotImplementedError() 159*635a8641SAndroid Build Coastguard Worker 160*635a8641SAndroid Build Coastguard Worker def clear(self): 161*635a8641SAndroid Build Coastguard Worker """Clears the cache. This method is not used by Jinja2 but should be 162*635a8641SAndroid Build Coastguard Worker implemented to allow applications to clear the bytecode cache used 163*635a8641SAndroid Build Coastguard Worker by a particular environment. 164*635a8641SAndroid Build Coastguard Worker """ 165*635a8641SAndroid Build Coastguard Worker 166*635a8641SAndroid Build Coastguard Worker def get_cache_key(self, name, filename=None): 167*635a8641SAndroid Build Coastguard Worker """Returns the unique hash key for this template name.""" 168*635a8641SAndroid Build Coastguard Worker hash = sha1(name.encode('utf-8')) 169*635a8641SAndroid Build Coastguard Worker if filename is not None: 170*635a8641SAndroid Build Coastguard Worker filename = '|' + filename 171*635a8641SAndroid Build Coastguard Worker if isinstance(filename, text_type): 172*635a8641SAndroid Build Coastguard Worker filename = filename.encode('utf-8') 173*635a8641SAndroid Build Coastguard Worker hash.update(filename) 174*635a8641SAndroid Build Coastguard Worker return hash.hexdigest() 175*635a8641SAndroid Build Coastguard Worker 176*635a8641SAndroid Build Coastguard Worker def get_source_checksum(self, source): 177*635a8641SAndroid Build Coastguard Worker """Returns a checksum for the source.""" 178*635a8641SAndroid Build Coastguard Worker return sha1(source.encode('utf-8')).hexdigest() 179*635a8641SAndroid Build Coastguard Worker 180*635a8641SAndroid Build Coastguard Worker def get_bucket(self, environment, name, filename, source): 181*635a8641SAndroid Build Coastguard Worker """Return a cache bucket for the given template. All arguments are 182*635a8641SAndroid Build Coastguard Worker mandatory but filename may be `None`. 183*635a8641SAndroid Build Coastguard Worker """ 184*635a8641SAndroid Build Coastguard Worker key = self.get_cache_key(name, filename) 185*635a8641SAndroid Build Coastguard Worker checksum = self.get_source_checksum(source) 186*635a8641SAndroid Build Coastguard Worker bucket = Bucket(environment, key, checksum) 187*635a8641SAndroid Build Coastguard Worker self.load_bytecode(bucket) 188*635a8641SAndroid Build Coastguard Worker return bucket 189*635a8641SAndroid Build Coastguard Worker 190*635a8641SAndroid Build Coastguard Worker def set_bucket(self, bucket): 191*635a8641SAndroid Build Coastguard Worker """Put the bucket into the cache.""" 192*635a8641SAndroid Build Coastguard Worker self.dump_bytecode(bucket) 193*635a8641SAndroid Build Coastguard Worker 194*635a8641SAndroid Build Coastguard Worker 195*635a8641SAndroid Build Coastguard Workerclass FileSystemBytecodeCache(BytecodeCache): 196*635a8641SAndroid Build Coastguard Worker """A bytecode cache that stores bytecode on the filesystem. It accepts 197*635a8641SAndroid Build Coastguard Worker two arguments: The directory where the cache items are stored and a 198*635a8641SAndroid Build Coastguard Worker pattern string that is used to build the filename. 199*635a8641SAndroid Build Coastguard Worker 200*635a8641SAndroid Build Coastguard Worker If no directory is specified a default cache directory is selected. On 201*635a8641SAndroid Build Coastguard Worker Windows the user's temp directory is used, on UNIX systems a directory 202*635a8641SAndroid Build Coastguard Worker is created for the user in the system temp directory. 203*635a8641SAndroid Build Coastguard Worker 204*635a8641SAndroid Build Coastguard Worker The pattern can be used to have multiple separate caches operate on the 205*635a8641SAndroid Build Coastguard Worker same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` 206*635a8641SAndroid Build Coastguard Worker is replaced with the cache key. 207*635a8641SAndroid Build Coastguard Worker 208*635a8641SAndroid Build Coastguard Worker >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') 209*635a8641SAndroid Build Coastguard Worker 210*635a8641SAndroid Build Coastguard Worker This bytecode cache supports clearing of the cache using the clear method. 211*635a8641SAndroid Build Coastguard Worker """ 212*635a8641SAndroid Build Coastguard Worker 213*635a8641SAndroid Build Coastguard Worker def __init__(self, directory=None, pattern='__jinja2_%s.cache'): 214*635a8641SAndroid Build Coastguard Worker if directory is None: 215*635a8641SAndroid Build Coastguard Worker directory = self._get_default_cache_dir() 216*635a8641SAndroid Build Coastguard Worker self.directory = directory 217*635a8641SAndroid Build Coastguard Worker self.pattern = pattern 218*635a8641SAndroid Build Coastguard Worker 219*635a8641SAndroid Build Coastguard Worker def _get_default_cache_dir(self): 220*635a8641SAndroid Build Coastguard Worker def _unsafe_dir(): 221*635a8641SAndroid Build Coastguard Worker raise RuntimeError('Cannot determine safe temp directory. You ' 222*635a8641SAndroid Build Coastguard Worker 'need to explicitly provide one.') 223*635a8641SAndroid Build Coastguard Worker 224*635a8641SAndroid Build Coastguard Worker tmpdir = tempfile.gettempdir() 225*635a8641SAndroid Build Coastguard Worker 226*635a8641SAndroid Build Coastguard Worker # On windows the temporary directory is used specific unless 227*635a8641SAndroid Build Coastguard Worker # explicitly forced otherwise. We can just use that. 228*635a8641SAndroid Build Coastguard Worker if os.name == 'nt': 229*635a8641SAndroid Build Coastguard Worker return tmpdir 230*635a8641SAndroid Build Coastguard Worker if not hasattr(os, 'getuid'): 231*635a8641SAndroid Build Coastguard Worker _unsafe_dir() 232*635a8641SAndroid Build Coastguard Worker 233*635a8641SAndroid Build Coastguard Worker dirname = '_jinja2-cache-%d' % os.getuid() 234*635a8641SAndroid Build Coastguard Worker actual_dir = os.path.join(tmpdir, dirname) 235*635a8641SAndroid Build Coastguard Worker 236*635a8641SAndroid Build Coastguard Worker try: 237*635a8641SAndroid Build Coastguard Worker os.mkdir(actual_dir, stat.S_IRWXU) 238*635a8641SAndroid Build Coastguard Worker except OSError as e: 239*635a8641SAndroid Build Coastguard Worker if e.errno != errno.EEXIST: 240*635a8641SAndroid Build Coastguard Worker raise 241*635a8641SAndroid Build Coastguard Worker try: 242*635a8641SAndroid Build Coastguard Worker os.chmod(actual_dir, stat.S_IRWXU) 243*635a8641SAndroid Build Coastguard Worker actual_dir_stat = os.lstat(actual_dir) 244*635a8641SAndroid Build Coastguard Worker if actual_dir_stat.st_uid != os.getuid() \ 245*635a8641SAndroid Build Coastguard Worker or not stat.S_ISDIR(actual_dir_stat.st_mode) \ 246*635a8641SAndroid Build Coastguard Worker or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU: 247*635a8641SAndroid Build Coastguard Worker _unsafe_dir() 248*635a8641SAndroid Build Coastguard Worker except OSError as e: 249*635a8641SAndroid Build Coastguard Worker if e.errno != errno.EEXIST: 250*635a8641SAndroid Build Coastguard Worker raise 251*635a8641SAndroid Build Coastguard Worker 252*635a8641SAndroid Build Coastguard Worker actual_dir_stat = os.lstat(actual_dir) 253*635a8641SAndroid Build Coastguard Worker if actual_dir_stat.st_uid != os.getuid() \ 254*635a8641SAndroid Build Coastguard Worker or not stat.S_ISDIR(actual_dir_stat.st_mode) \ 255*635a8641SAndroid Build Coastguard Worker or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU: 256*635a8641SAndroid Build Coastguard Worker _unsafe_dir() 257*635a8641SAndroid Build Coastguard Worker 258*635a8641SAndroid Build Coastguard Worker return actual_dir 259*635a8641SAndroid Build Coastguard Worker 260*635a8641SAndroid Build Coastguard Worker def _get_cache_filename(self, bucket): 261*635a8641SAndroid Build Coastguard Worker return path.join(self.directory, self.pattern % bucket.key) 262*635a8641SAndroid Build Coastguard Worker 263*635a8641SAndroid Build Coastguard Worker def load_bytecode(self, bucket): 264*635a8641SAndroid Build Coastguard Worker f = open_if_exists(self._get_cache_filename(bucket), 'rb') 265*635a8641SAndroid Build Coastguard Worker if f is not None: 266*635a8641SAndroid Build Coastguard Worker try: 267*635a8641SAndroid Build Coastguard Worker bucket.load_bytecode(f) 268*635a8641SAndroid Build Coastguard Worker finally: 269*635a8641SAndroid Build Coastguard Worker f.close() 270*635a8641SAndroid Build Coastguard Worker 271*635a8641SAndroid Build Coastguard Worker def dump_bytecode(self, bucket): 272*635a8641SAndroid Build Coastguard Worker f = open(self._get_cache_filename(bucket), 'wb') 273*635a8641SAndroid Build Coastguard Worker try: 274*635a8641SAndroid Build Coastguard Worker bucket.write_bytecode(f) 275*635a8641SAndroid Build Coastguard Worker finally: 276*635a8641SAndroid Build Coastguard Worker f.close() 277*635a8641SAndroid Build Coastguard Worker 278*635a8641SAndroid Build Coastguard Worker def clear(self): 279*635a8641SAndroid Build Coastguard Worker # imported lazily here because google app-engine doesn't support 280*635a8641SAndroid Build Coastguard Worker # write access on the file system and the function does not exist 281*635a8641SAndroid Build Coastguard Worker # normally. 282*635a8641SAndroid Build Coastguard Worker from os import remove 283*635a8641SAndroid Build Coastguard Worker files = fnmatch.filter(listdir(self.directory), self.pattern % '*') 284*635a8641SAndroid Build Coastguard Worker for filename in files: 285*635a8641SAndroid Build Coastguard Worker try: 286*635a8641SAndroid Build Coastguard Worker remove(path.join(self.directory, filename)) 287*635a8641SAndroid Build Coastguard Worker except OSError: 288*635a8641SAndroid Build Coastguard Worker pass 289*635a8641SAndroid Build Coastguard Worker 290*635a8641SAndroid Build Coastguard Worker 291*635a8641SAndroid Build Coastguard Workerclass MemcachedBytecodeCache(BytecodeCache): 292*635a8641SAndroid Build Coastguard Worker """This class implements a bytecode cache that uses a memcache cache for 293*635a8641SAndroid Build Coastguard Worker storing the information. It does not enforce a specific memcache library 294*635a8641SAndroid Build Coastguard Worker (tummy's memcache or cmemcache) but will accept any class that provides 295*635a8641SAndroid Build Coastguard Worker the minimal interface required. 296*635a8641SAndroid Build Coastguard Worker 297*635a8641SAndroid Build Coastguard Worker Libraries compatible with this class: 298*635a8641SAndroid Build Coastguard Worker 299*635a8641SAndroid Build Coastguard Worker - `werkzeug <http://werkzeug.pocoo.org/>`_.contrib.cache 300*635a8641SAndroid Build Coastguard Worker - `python-memcached <https://www.tummy.com/Community/software/python-memcached/>`_ 301*635a8641SAndroid Build Coastguard Worker - `cmemcache <http://gijsbert.org/cmemcache/>`_ 302*635a8641SAndroid Build Coastguard Worker 303*635a8641SAndroid Build Coastguard Worker (Unfortunately the django cache interface is not compatible because it 304*635a8641SAndroid Build Coastguard Worker does not support storing binary data, only unicode. You can however pass 305*635a8641SAndroid Build Coastguard Worker the underlying cache client to the bytecode cache which is available 306*635a8641SAndroid Build Coastguard Worker as `django.core.cache.cache._client`.) 307*635a8641SAndroid Build Coastguard Worker 308*635a8641SAndroid Build Coastguard Worker The minimal interface for the client passed to the constructor is this: 309*635a8641SAndroid Build Coastguard Worker 310*635a8641SAndroid Build Coastguard Worker .. class:: MinimalClientInterface 311*635a8641SAndroid Build Coastguard Worker 312*635a8641SAndroid Build Coastguard Worker .. method:: set(key, value[, timeout]) 313*635a8641SAndroid Build Coastguard Worker 314*635a8641SAndroid Build Coastguard Worker Stores the bytecode in the cache. `value` is a string and 315*635a8641SAndroid Build Coastguard Worker `timeout` the timeout of the key. If timeout is not provided 316*635a8641SAndroid Build Coastguard Worker a default timeout or no timeout should be assumed, if it's 317*635a8641SAndroid Build Coastguard Worker provided it's an integer with the number of seconds the cache 318*635a8641SAndroid Build Coastguard Worker item should exist. 319*635a8641SAndroid Build Coastguard Worker 320*635a8641SAndroid Build Coastguard Worker .. method:: get(key) 321*635a8641SAndroid Build Coastguard Worker 322*635a8641SAndroid Build Coastguard Worker Returns the value for the cache key. If the item does not 323*635a8641SAndroid Build Coastguard Worker exist in the cache the return value must be `None`. 324*635a8641SAndroid Build Coastguard Worker 325*635a8641SAndroid Build Coastguard Worker The other arguments to the constructor are the prefix for all keys that 326*635a8641SAndroid Build Coastguard Worker is added before the actual cache key and the timeout for the bytecode in 327*635a8641SAndroid Build Coastguard Worker the cache system. We recommend a high (or no) timeout. 328*635a8641SAndroid Build Coastguard Worker 329*635a8641SAndroid Build Coastguard Worker This bytecode cache does not support clearing of used items in the cache. 330*635a8641SAndroid Build Coastguard Worker The clear method is a no-operation function. 331*635a8641SAndroid Build Coastguard Worker 332*635a8641SAndroid Build Coastguard Worker .. versionadded:: 2.7 333*635a8641SAndroid Build Coastguard Worker Added support for ignoring memcache errors through the 334*635a8641SAndroid Build Coastguard Worker `ignore_memcache_errors` parameter. 335*635a8641SAndroid Build Coastguard Worker """ 336*635a8641SAndroid Build Coastguard Worker 337*635a8641SAndroid Build Coastguard Worker def __init__(self, client, prefix='jinja2/bytecode/', timeout=None, 338*635a8641SAndroid Build Coastguard Worker ignore_memcache_errors=True): 339*635a8641SAndroid Build Coastguard Worker self.client = client 340*635a8641SAndroid Build Coastguard Worker self.prefix = prefix 341*635a8641SAndroid Build Coastguard Worker self.timeout = timeout 342*635a8641SAndroid Build Coastguard Worker self.ignore_memcache_errors = ignore_memcache_errors 343*635a8641SAndroid Build Coastguard Worker 344*635a8641SAndroid Build Coastguard Worker def load_bytecode(self, bucket): 345*635a8641SAndroid Build Coastguard Worker try: 346*635a8641SAndroid Build Coastguard Worker code = self.client.get(self.prefix + bucket.key) 347*635a8641SAndroid Build Coastguard Worker except Exception: 348*635a8641SAndroid Build Coastguard Worker if not self.ignore_memcache_errors: 349*635a8641SAndroid Build Coastguard Worker raise 350*635a8641SAndroid Build Coastguard Worker code = None 351*635a8641SAndroid Build Coastguard Worker if code is not None: 352*635a8641SAndroid Build Coastguard Worker bucket.bytecode_from_string(code) 353*635a8641SAndroid Build Coastguard Worker 354*635a8641SAndroid Build Coastguard Worker def dump_bytecode(self, bucket): 355*635a8641SAndroid Build Coastguard Worker args = (self.prefix + bucket.key, bucket.bytecode_to_string()) 356*635a8641SAndroid Build Coastguard Worker if self.timeout is not None: 357*635a8641SAndroid Build Coastguard Worker args += (self.timeout,) 358*635a8641SAndroid Build Coastguard Worker try: 359*635a8641SAndroid Build Coastguard Worker self.client.set(*args) 360*635a8641SAndroid Build Coastguard Worker except Exception: 361*635a8641SAndroid Build Coastguard Worker if not self.ignore_memcache_errors: 362*635a8641SAndroid Build Coastguard Worker raise 363