11cb0ef41Sopenharmony_ci# -*- coding: utf-8 -*- 21cb0ef41Sopenharmony_ci""" 31cb0ef41Sopenharmony_ci jinja2.bccache 41cb0ef41Sopenharmony_ci ~~~~~~~~~~~~~~ 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci This module implements the bytecode cache system Jinja is optionally 71cb0ef41Sopenharmony_ci using. This is useful if you have very complex template situations and 81cb0ef41Sopenharmony_ci the compiliation of all those templates slow down your application too 91cb0ef41Sopenharmony_ci much. 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci Situations where this is useful are often forking web applications that 121cb0ef41Sopenharmony_ci are initialized on the first request. 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci :copyright: (c) 2017 by the Jinja Team. 151cb0ef41Sopenharmony_ci :license: BSD. 161cb0ef41Sopenharmony_ci""" 171cb0ef41Sopenharmony_cifrom os import path, listdir 181cb0ef41Sopenharmony_ciimport os 191cb0ef41Sopenharmony_ciimport sys 201cb0ef41Sopenharmony_ciimport stat 211cb0ef41Sopenharmony_ciimport errno 221cb0ef41Sopenharmony_ciimport marshal 231cb0ef41Sopenharmony_ciimport tempfile 241cb0ef41Sopenharmony_ciimport fnmatch 251cb0ef41Sopenharmony_cifrom hashlib import sha1 261cb0ef41Sopenharmony_cifrom jinja2.utils import open_if_exists 271cb0ef41Sopenharmony_cifrom jinja2._compat import BytesIO, pickle, PY2, text_type 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci# marshal works better on 3.x, one hack less required 311cb0ef41Sopenharmony_ciif not PY2: 321cb0ef41Sopenharmony_ci marshal_dump = marshal.dump 331cb0ef41Sopenharmony_ci marshal_load = marshal.load 341cb0ef41Sopenharmony_cielse: 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci def marshal_dump(code, f): 371cb0ef41Sopenharmony_ci if isinstance(f, file): 381cb0ef41Sopenharmony_ci marshal.dump(code, f) 391cb0ef41Sopenharmony_ci else: 401cb0ef41Sopenharmony_ci f.write(marshal.dumps(code)) 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci def marshal_load(f): 431cb0ef41Sopenharmony_ci if isinstance(f, file): 441cb0ef41Sopenharmony_ci return marshal.load(f) 451cb0ef41Sopenharmony_ci return marshal.loads(f.read()) 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_cibc_version = 3 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci# magic version used to only change with new jinja versions. With 2.6 511cb0ef41Sopenharmony_ci# we change this to also take Python version changes into account. The 521cb0ef41Sopenharmony_ci# reason for this is that Python tends to segfault if fed earlier bytecode 531cb0ef41Sopenharmony_ci# versions because someone thought it would be a good idea to reuse opcodes 541cb0ef41Sopenharmony_ci# or make Python incompatible with earlier versions. 551cb0ef41Sopenharmony_cibc_magic = 'j2'.encode('ascii') + \ 561cb0ef41Sopenharmony_ci pickle.dumps(bc_version, 2) + \ 571cb0ef41Sopenharmony_ci pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1]) 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ciclass Bucket(object): 611cb0ef41Sopenharmony_ci """Buckets are used to store the bytecode for one template. It's created 621cb0ef41Sopenharmony_ci and initialized by the bytecode cache and passed to the loading functions. 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci The buckets get an internal checksum from the cache assigned and use this 651cb0ef41Sopenharmony_ci to automatically reject outdated cache material. Individual bytecode 661cb0ef41Sopenharmony_ci cache subclasses don't have to care about cache invalidation. 671cb0ef41Sopenharmony_ci """ 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci def __init__(self, environment, key, checksum): 701cb0ef41Sopenharmony_ci self.environment = environment 711cb0ef41Sopenharmony_ci self.key = key 721cb0ef41Sopenharmony_ci self.checksum = checksum 731cb0ef41Sopenharmony_ci self.reset() 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci def reset(self): 761cb0ef41Sopenharmony_ci """Resets the bucket (unloads the bytecode).""" 771cb0ef41Sopenharmony_ci self.code = None 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci def load_bytecode(self, f): 801cb0ef41Sopenharmony_ci """Loads bytecode from a file or file like object.""" 811cb0ef41Sopenharmony_ci # make sure the magic header is correct 821cb0ef41Sopenharmony_ci magic = f.read(len(bc_magic)) 831cb0ef41Sopenharmony_ci if magic != bc_magic: 841cb0ef41Sopenharmony_ci self.reset() 851cb0ef41Sopenharmony_ci return 861cb0ef41Sopenharmony_ci # the source code of the file changed, we need to reload 871cb0ef41Sopenharmony_ci checksum = pickle.load(f) 881cb0ef41Sopenharmony_ci if self.checksum != checksum: 891cb0ef41Sopenharmony_ci self.reset() 901cb0ef41Sopenharmony_ci return 911cb0ef41Sopenharmony_ci # if marshal_load fails then we need to reload 921cb0ef41Sopenharmony_ci try: 931cb0ef41Sopenharmony_ci self.code = marshal_load(f) 941cb0ef41Sopenharmony_ci except (EOFError, ValueError, TypeError): 951cb0ef41Sopenharmony_ci self.reset() 961cb0ef41Sopenharmony_ci return 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_ci def write_bytecode(self, f): 991cb0ef41Sopenharmony_ci """Dump the bytecode into the file or file like object passed.""" 1001cb0ef41Sopenharmony_ci if self.code is None: 1011cb0ef41Sopenharmony_ci raise TypeError('can\'t write empty bucket') 1021cb0ef41Sopenharmony_ci f.write(bc_magic) 1031cb0ef41Sopenharmony_ci pickle.dump(self.checksum, f, 2) 1041cb0ef41Sopenharmony_ci marshal_dump(self.code, f) 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci def bytecode_from_string(self, string): 1071cb0ef41Sopenharmony_ci """Load bytecode from a string.""" 1081cb0ef41Sopenharmony_ci self.load_bytecode(BytesIO(string)) 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci def bytecode_to_string(self): 1111cb0ef41Sopenharmony_ci """Return the bytecode as string.""" 1121cb0ef41Sopenharmony_ci out = BytesIO() 1131cb0ef41Sopenharmony_ci self.write_bytecode(out) 1141cb0ef41Sopenharmony_ci return out.getvalue() 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ciclass BytecodeCache(object): 1181cb0ef41Sopenharmony_ci """To implement your own bytecode cache you have to subclass this class 1191cb0ef41Sopenharmony_ci and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of 1201cb0ef41Sopenharmony_ci these methods are passed a :class:`~jinja2.bccache.Bucket`. 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci A very basic bytecode cache that saves the bytecode on the file system:: 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci from os import path 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci class MyCache(BytecodeCache): 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci def __init__(self, directory): 1291cb0ef41Sopenharmony_ci self.directory = directory 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci def load_bytecode(self, bucket): 1321cb0ef41Sopenharmony_ci filename = path.join(self.directory, bucket.key) 1331cb0ef41Sopenharmony_ci if path.exists(filename): 1341cb0ef41Sopenharmony_ci with open(filename, 'rb') as f: 1351cb0ef41Sopenharmony_ci bucket.load_bytecode(f) 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci def dump_bytecode(self, bucket): 1381cb0ef41Sopenharmony_ci filename = path.join(self.directory, bucket.key) 1391cb0ef41Sopenharmony_ci with open(filename, 'wb') as f: 1401cb0ef41Sopenharmony_ci bucket.write_bytecode(f) 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci A more advanced version of a filesystem based bytecode cache is part of 1431cb0ef41Sopenharmony_ci Jinja2. 1441cb0ef41Sopenharmony_ci """ 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci def load_bytecode(self, bucket): 1471cb0ef41Sopenharmony_ci """Subclasses have to override this method to load bytecode into a 1481cb0ef41Sopenharmony_ci bucket. If they are not able to find code in the cache for the 1491cb0ef41Sopenharmony_ci bucket, it must not do anything. 1501cb0ef41Sopenharmony_ci """ 1511cb0ef41Sopenharmony_ci raise NotImplementedError() 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci def dump_bytecode(self, bucket): 1541cb0ef41Sopenharmony_ci """Subclasses have to override this method to write the bytecode 1551cb0ef41Sopenharmony_ci from a bucket back to the cache. If it unable to do so it must not 1561cb0ef41Sopenharmony_ci fail silently but raise an exception. 1571cb0ef41Sopenharmony_ci """ 1581cb0ef41Sopenharmony_ci raise NotImplementedError() 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci def clear(self): 1611cb0ef41Sopenharmony_ci """Clears the cache. This method is not used by Jinja2 but should be 1621cb0ef41Sopenharmony_ci implemented to allow applications to clear the bytecode cache used 1631cb0ef41Sopenharmony_ci by a particular environment. 1641cb0ef41Sopenharmony_ci """ 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci def get_cache_key(self, name, filename=None): 1671cb0ef41Sopenharmony_ci """Returns the unique hash key for this template name.""" 1681cb0ef41Sopenharmony_ci hash = sha1(name.encode('utf-8')) 1691cb0ef41Sopenharmony_ci if filename is not None: 1701cb0ef41Sopenharmony_ci filename = '|' + filename 1711cb0ef41Sopenharmony_ci if isinstance(filename, text_type): 1721cb0ef41Sopenharmony_ci filename = filename.encode('utf-8') 1731cb0ef41Sopenharmony_ci hash.update(filename) 1741cb0ef41Sopenharmony_ci return hash.hexdigest() 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci def get_source_checksum(self, source): 1771cb0ef41Sopenharmony_ci """Returns a checksum for the source.""" 1781cb0ef41Sopenharmony_ci return sha1(source.encode('utf-8')).hexdigest() 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci def get_bucket(self, environment, name, filename, source): 1811cb0ef41Sopenharmony_ci """Return a cache bucket for the given template. All arguments are 1821cb0ef41Sopenharmony_ci mandatory but filename may be `None`. 1831cb0ef41Sopenharmony_ci """ 1841cb0ef41Sopenharmony_ci key = self.get_cache_key(name, filename) 1851cb0ef41Sopenharmony_ci checksum = self.get_source_checksum(source) 1861cb0ef41Sopenharmony_ci bucket = Bucket(environment, key, checksum) 1871cb0ef41Sopenharmony_ci self.load_bytecode(bucket) 1881cb0ef41Sopenharmony_ci return bucket 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci def set_bucket(self, bucket): 1911cb0ef41Sopenharmony_ci """Put the bucket into the cache.""" 1921cb0ef41Sopenharmony_ci self.dump_bytecode(bucket) 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ciclass FileSystemBytecodeCache(BytecodeCache): 1961cb0ef41Sopenharmony_ci """A bytecode cache that stores bytecode on the filesystem. It accepts 1971cb0ef41Sopenharmony_ci two arguments: The directory where the cache items are stored and a 1981cb0ef41Sopenharmony_ci pattern string that is used to build the filename. 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci If no directory is specified a default cache directory is selected. On 2011cb0ef41Sopenharmony_ci Windows the user's temp directory is used, on UNIX systems a directory 2021cb0ef41Sopenharmony_ci is created for the user in the system temp directory. 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci The pattern can be used to have multiple separate caches operate on the 2051cb0ef41Sopenharmony_ci same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` 2061cb0ef41Sopenharmony_ci is replaced with the cache key. 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci This bytecode cache supports clearing of the cache using the clear method. 2111cb0ef41Sopenharmony_ci """ 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci def __init__(self, directory=None, pattern='__jinja2_%s.cache'): 2141cb0ef41Sopenharmony_ci if directory is None: 2151cb0ef41Sopenharmony_ci directory = self._get_default_cache_dir() 2161cb0ef41Sopenharmony_ci self.directory = directory 2171cb0ef41Sopenharmony_ci self.pattern = pattern 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci def _get_default_cache_dir(self): 2201cb0ef41Sopenharmony_ci def _unsafe_dir(): 2211cb0ef41Sopenharmony_ci raise RuntimeError('Cannot determine safe temp directory. You ' 2221cb0ef41Sopenharmony_ci 'need to explicitly provide one.') 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci tmpdir = tempfile.gettempdir() 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci # On windows the temporary directory is used specific unless 2271cb0ef41Sopenharmony_ci # explicitly forced otherwise. We can just use that. 2281cb0ef41Sopenharmony_ci if os.name == 'nt': 2291cb0ef41Sopenharmony_ci return tmpdir 2301cb0ef41Sopenharmony_ci if not hasattr(os, 'getuid'): 2311cb0ef41Sopenharmony_ci _unsafe_dir() 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci dirname = '_jinja2-cache-%d' % os.getuid() 2341cb0ef41Sopenharmony_ci actual_dir = os.path.join(tmpdir, dirname) 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci try: 2371cb0ef41Sopenharmony_ci os.mkdir(actual_dir, stat.S_IRWXU) 2381cb0ef41Sopenharmony_ci except OSError as e: 2391cb0ef41Sopenharmony_ci if e.errno != errno.EEXIST: 2401cb0ef41Sopenharmony_ci raise 2411cb0ef41Sopenharmony_ci try: 2421cb0ef41Sopenharmony_ci os.chmod(actual_dir, stat.S_IRWXU) 2431cb0ef41Sopenharmony_ci actual_dir_stat = os.lstat(actual_dir) 2441cb0ef41Sopenharmony_ci if actual_dir_stat.st_uid != os.getuid() \ 2451cb0ef41Sopenharmony_ci or not stat.S_ISDIR(actual_dir_stat.st_mode) \ 2461cb0ef41Sopenharmony_ci or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU: 2471cb0ef41Sopenharmony_ci _unsafe_dir() 2481cb0ef41Sopenharmony_ci except OSError as e: 2491cb0ef41Sopenharmony_ci if e.errno != errno.EEXIST: 2501cb0ef41Sopenharmony_ci raise 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci actual_dir_stat = os.lstat(actual_dir) 2531cb0ef41Sopenharmony_ci if actual_dir_stat.st_uid != os.getuid() \ 2541cb0ef41Sopenharmony_ci or not stat.S_ISDIR(actual_dir_stat.st_mode) \ 2551cb0ef41Sopenharmony_ci or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU: 2561cb0ef41Sopenharmony_ci _unsafe_dir() 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci return actual_dir 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci def _get_cache_filename(self, bucket): 2611cb0ef41Sopenharmony_ci return path.join(self.directory, self.pattern % bucket.key) 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci def load_bytecode(self, bucket): 2641cb0ef41Sopenharmony_ci f = open_if_exists(self._get_cache_filename(bucket), 'rb') 2651cb0ef41Sopenharmony_ci if f is not None: 2661cb0ef41Sopenharmony_ci try: 2671cb0ef41Sopenharmony_ci bucket.load_bytecode(f) 2681cb0ef41Sopenharmony_ci finally: 2691cb0ef41Sopenharmony_ci f.close() 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci def dump_bytecode(self, bucket): 2721cb0ef41Sopenharmony_ci f = open(self._get_cache_filename(bucket), 'wb') 2731cb0ef41Sopenharmony_ci try: 2741cb0ef41Sopenharmony_ci bucket.write_bytecode(f) 2751cb0ef41Sopenharmony_ci finally: 2761cb0ef41Sopenharmony_ci f.close() 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci def clear(self): 2791cb0ef41Sopenharmony_ci # imported lazily here because google app-engine doesn't support 2801cb0ef41Sopenharmony_ci # write access on the file system and the function does not exist 2811cb0ef41Sopenharmony_ci # normally. 2821cb0ef41Sopenharmony_ci from os import remove 2831cb0ef41Sopenharmony_ci files = fnmatch.filter(listdir(self.directory), self.pattern % '*') 2841cb0ef41Sopenharmony_ci for filename in files: 2851cb0ef41Sopenharmony_ci try: 2861cb0ef41Sopenharmony_ci remove(path.join(self.directory, filename)) 2871cb0ef41Sopenharmony_ci except OSError: 2881cb0ef41Sopenharmony_ci pass 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ciclass MemcachedBytecodeCache(BytecodeCache): 2921cb0ef41Sopenharmony_ci """This class implements a bytecode cache that uses a memcache cache for 2931cb0ef41Sopenharmony_ci storing the information. It does not enforce a specific memcache library 2941cb0ef41Sopenharmony_ci (tummy's memcache or cmemcache) but will accept any class that provides 2951cb0ef41Sopenharmony_ci the minimal interface required. 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci Libraries compatible with this class: 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci - `werkzeug <http://werkzeug.pocoo.org/>`_.contrib.cache 3001cb0ef41Sopenharmony_ci - `python-memcached <https://www.tummy.com/Community/software/python-memcached/>`_ 3011cb0ef41Sopenharmony_ci - `cmemcache <http://gijsbert.org/cmemcache/>`_ 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci (Unfortunately the django cache interface is not compatible because it 3041cb0ef41Sopenharmony_ci does not support storing binary data, only unicode. You can however pass 3051cb0ef41Sopenharmony_ci the underlying cache client to the bytecode cache which is available 3061cb0ef41Sopenharmony_ci as `django.core.cache.cache._client`.) 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci The minimal interface for the client passed to the constructor is this: 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci .. class:: MinimalClientInterface 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci .. method:: set(key, value[, timeout]) 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci Stores the bytecode in the cache. `value` is a string and 3151cb0ef41Sopenharmony_ci `timeout` the timeout of the key. If timeout is not provided 3161cb0ef41Sopenharmony_ci a default timeout or no timeout should be assumed, if it's 3171cb0ef41Sopenharmony_ci provided it's an integer with the number of seconds the cache 3181cb0ef41Sopenharmony_ci item should exist. 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci .. method:: get(key) 3211cb0ef41Sopenharmony_ci 3221cb0ef41Sopenharmony_ci Returns the value for the cache key. If the item does not 3231cb0ef41Sopenharmony_ci exist in the cache the return value must be `None`. 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci The other arguments to the constructor are the prefix for all keys that 3261cb0ef41Sopenharmony_ci is added before the actual cache key and the timeout for the bytecode in 3271cb0ef41Sopenharmony_ci the cache system. We recommend a high (or no) timeout. 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci This bytecode cache does not support clearing of used items in the cache. 3301cb0ef41Sopenharmony_ci The clear method is a no-operation function. 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci .. versionadded:: 2.7 3331cb0ef41Sopenharmony_ci Added support for ignoring memcache errors through the 3341cb0ef41Sopenharmony_ci `ignore_memcache_errors` parameter. 3351cb0ef41Sopenharmony_ci """ 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci def __init__(self, client, prefix='jinja2/bytecode/', timeout=None, 3381cb0ef41Sopenharmony_ci ignore_memcache_errors=True): 3391cb0ef41Sopenharmony_ci self.client = client 3401cb0ef41Sopenharmony_ci self.prefix = prefix 3411cb0ef41Sopenharmony_ci self.timeout = timeout 3421cb0ef41Sopenharmony_ci self.ignore_memcache_errors = ignore_memcache_errors 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci def load_bytecode(self, bucket): 3451cb0ef41Sopenharmony_ci try: 3461cb0ef41Sopenharmony_ci code = self.client.get(self.prefix + bucket.key) 3471cb0ef41Sopenharmony_ci except Exception: 3481cb0ef41Sopenharmony_ci if not self.ignore_memcache_errors: 3491cb0ef41Sopenharmony_ci raise 3501cb0ef41Sopenharmony_ci code = None 3511cb0ef41Sopenharmony_ci if code is not None: 3521cb0ef41Sopenharmony_ci bucket.bytecode_from_string(code) 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci def dump_bytecode(self, bucket): 3551cb0ef41Sopenharmony_ci args = (self.prefix + bucket.key, bucket.bytecode_to_string()) 3561cb0ef41Sopenharmony_ci if self.timeout is not None: 3571cb0ef41Sopenharmony_ci args += (self.timeout,) 3581cb0ef41Sopenharmony_ci try: 3591cb0ef41Sopenharmony_ci self.client.set(*args) 3601cb0ef41Sopenharmony_ci except Exception: 3611cb0ef41Sopenharmony_ci if not self.ignore_memcache_errors: 3621cb0ef41Sopenharmony_ci raise 363