1 # -*- coding: utf-8 -*-
6 This module implements the bytecode cache system Jinja is optionally
7 using. This is useful if you have very complex template situations and
8 the compiliation of all those templates slow down your application too
11 Situations where this is useful are often forking web applications that
12 are initialized on the first request.
14 :copyright: (c) 2010 by the Jinja Team.
17 from os
import path
, listdir
22 from hashlib
import sha1
23 from jinja2
.utils
import open_if_exists
24 from jinja2
._compat
import BytesIO
, pickle
, PY2
, text_type
27 # marshal works better on 3.x, one hack less required
29 marshal_dump
= marshal
.dump
30 marshal_load
= marshal
.load
33 def marshal_dump(code
, f
):
34 if isinstance(f
, file):
37 f
.write(marshal
.dumps(code
))
40 if isinstance(f
, file):
41 return marshal
.load(f
)
42 return marshal
.loads(f
.read())
47 # magic version used to only change with new jinja versions. With 2.6
48 # we change this to also take Python version changes into account. The
49 # reason for this is that Python tends to segfault if fed earlier bytecode
50 # versions because someone thought it would be a good idea to reuse opcodes
51 # or make Python incompatible with earlier versions.
52 bc_magic
= 'j2'.encode('ascii') + \
53 pickle
.dumps(bc_version
, 2) + \
54 pickle
.dumps((sys
.version_info
[0] << 24) | sys
.version_info
[1])
58 """Buckets are used to store the bytecode for one template. It's created
59 and initialized by the bytecode cache and passed to the loading functions.
61 The buckets get an internal checksum from the cache assigned and use this
62 to automatically reject outdated cache material. Individual bytecode
63 cache subclasses don't have to care about cache invalidation.
66 def __init__(self
, environment
, key
, checksum
):
67 self
.environment
= environment
69 self
.checksum
= checksum
73 """Resets the bucket (unloads the bytecode)."""
76 def load_bytecode(self
, f
):
77 """Loads bytecode from a file or file like object."""
78 # make sure the magic header is correct
79 magic
= f
.read(len(bc_magic
))
83 # the source code of the file changed, we need to reload
84 checksum
= pickle
.load(f
)
85 if self
.checksum
!= checksum
:
88 self
.code
= marshal_load(f
)
90 def write_bytecode(self
, f
):
91 """Dump the bytecode into the file or file like object passed."""
93 raise TypeError('can\'t write empty bucket')
95 pickle
.dump(self
.checksum
, f
, 2)
96 marshal_dump(self
.code
, f
)
98 def bytecode_from_string(self
, string
):
99 """Load bytecode from a string."""
100 self
.load_bytecode(BytesIO(string
))
102 def bytecode_to_string(self
):
103 """Return the bytecode as string."""
105 self
.write_bytecode(out
)
106 return out
.getvalue()
109 class BytecodeCache(object):
110 """To implement your own bytecode cache you have to subclass this class
111 and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
112 these methods are passed a :class:`~jinja2.bccache.Bucket`.
114 A very basic bytecode cache that saves the bytecode on the file system::
118 class MyCache(BytecodeCache):
120 def __init__(self, directory):
121 self.directory = directory
123 def load_bytecode(self, bucket):
124 filename = path.join(self.directory, bucket.key)
125 if path.exists(filename):
126 with open(filename, 'rb') as f:
127 bucket.load_bytecode(f)
129 def dump_bytecode(self, bucket):
130 filename = path.join(self.directory, bucket.key)
131 with open(filename, 'wb') as f:
132 bucket.write_bytecode(f)
134 A more advanced version of a filesystem based bytecode cache is part of
138 def load_bytecode(self
, bucket
):
139 """Subclasses have to override this method to load bytecode into a
140 bucket. If they are not able to find code in the cache for the
141 bucket, it must not do anything.
143 raise NotImplementedError()
145 def dump_bytecode(self
, bucket
):
146 """Subclasses have to override this method to write the bytecode
147 from a bucket back to the cache. If it unable to do so it must not
148 fail silently but raise an exception.
150 raise NotImplementedError()
153 """Clears the cache. This method is not used by Jinja2 but should be
154 implemented to allow applications to clear the bytecode cache used
155 by a particular environment.
158 def get_cache_key(self
, name
, filename
=None):
159 """Returns the unique hash key for this template name."""
160 hash = sha1(name
.encode('utf-8'))
161 if filename
is not None:
162 filename
= '|' + filename
163 if isinstance(filename
, text_type
):
164 filename
= filename
.encode('utf-8')
165 hash.update(filename
)
166 return hash.hexdigest()
168 def get_source_checksum(self
, source
):
169 """Returns a checksum for the source."""
170 return sha1(source
.encode('utf-8')).hexdigest()
172 def get_bucket(self
, environment
, name
, filename
, source
):
173 """Return a cache bucket for the given template. All arguments are
174 mandatory but filename may be `None`.
176 key
= self
.get_cache_key(name
, filename
)
177 checksum
= self
.get_source_checksum(source
)
178 bucket
= Bucket(environment
, key
, checksum
)
179 self
.load_bytecode(bucket
)
182 def set_bucket(self
, bucket
):
183 """Put the bucket into the cache."""
184 self
.dump_bytecode(bucket
)
187 class FileSystemBytecodeCache(BytecodeCache
):
188 """A bytecode cache that stores bytecode on the filesystem. It accepts
189 two arguments: The directory where the cache items are stored and a
190 pattern string that is used to build the filename.
192 If no directory is specified the system temporary items folder is used.
194 The pattern can be used to have multiple separate caches operate on the
195 same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
196 is replaced with the cache key.
198 >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
200 This bytecode cache supports clearing of the cache using the clear method.
203 def __init__(self
, directory
=None, pattern
='__jinja2_%s.cache'):
204 if directory
is None:
205 directory
= tempfile
.gettempdir()
206 self
.directory
= directory
207 self
.pattern
= pattern
209 def _get_cache_filename(self
, bucket
):
210 return path
.join(self
.directory
, self
.pattern
% bucket
.key
)
212 def load_bytecode(self
, bucket
):
213 f
= open_if_exists(self
._get
_cache
_filename
(bucket
), 'rb')
216 bucket
.load_bytecode(f
)
220 def dump_bytecode(self
, bucket
):
221 f
= open(self
._get
_cache
_filename
(bucket
), 'wb')
223 bucket
.write_bytecode(f
)
228 # imported lazily here because google app-engine doesn't support
229 # write access on the file system and the function does not exist
231 from os
import remove
232 files
= fnmatch
.filter(listdir(self
.directory
), self
.pattern
% '*')
233 for filename
in files
:
235 remove(path
.join(self
.directory
, filename
))
240 class MemcachedBytecodeCache(BytecodeCache
):
241 """This class implements a bytecode cache that uses a memcache cache for
242 storing the information. It does not enforce a specific memcache library
243 (tummy's memcache or cmemcache) but will accept any class that provides
244 the minimal interface required.
246 Libraries compatible with this class:
248 - `werkzeug <http://werkzeug.pocoo.org/>`_.contrib.cache
249 - `python-memcached <http://www.tummy.com/Community/software/python-memcached/>`_
250 - `cmemcache <http://gijsbert.org/cmemcache/>`_
252 (Unfortunately the django cache interface is not compatible because it
253 does not support storing binary data, only unicode. You can however pass
254 the underlying cache client to the bytecode cache which is available
255 as `django.core.cache.cache._client`.)
257 The minimal interface for the client passed to the constructor is this:
259 .. class:: MinimalClientInterface
261 .. method:: set(key, value[, timeout])
263 Stores the bytecode in the cache. `value` is a string and
264 `timeout` the timeout of the key. If timeout is not provided
265 a default timeout or no timeout should be assumed, if it's
266 provided it's an integer with the number of seconds the cache
271 Returns the value for the cache key. If the item does not
272 exist in the cache the return value must be `None`.
274 The other arguments to the constructor are the prefix for all keys that
275 is added before the actual cache key and the timeout for the bytecode in
276 the cache system. We recommend a high (or no) timeout.
278 This bytecode cache does not support clearing of used items in the cache.
279 The clear method is a no-operation function.
281 .. versionadded:: 2.7
282 Added support for ignoring memcache errors through the
283 `ignore_memcache_errors` parameter.
286 def __init__(self
, client
, prefix
='jinja2/bytecode/', timeout
=None,
287 ignore_memcache_errors
=True):
290 self
.timeout
= timeout
291 self
.ignore_memcache_errors
= ignore_memcache_errors
293 def load_bytecode(self
, bucket
):
295 code
= self
.client
.get(self
.prefix
+ bucket
.key
)
297 if not self
.ignore_memcache_errors
:
301 bucket
.bytecode_from_string(code
)
303 def dump_bytecode(self
, bucket
):
304 args
= (self
.prefix
+ bucket
.key
, bucket
.bytecode_to_string())
305 if self
.timeout
is not None:
306 args
+= (self
.timeout
,)
308 self
.client
.set(*args
)
310 if not self
.ignore_memcache_errors
: