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