1+ from jinja2 import nodes
2+ from jinja2 .ext import Extension
3+
4+
5+ class FragmentCacheExtension (Extension ):
6+ # a set of names that trigger the extension.
7+ tags = {"cache" }
8+
9+ def __init__ (self , environment ):
10+ super ().__init__ (environment )
11+
12+ # add the defaults to the environment
13+ environment .extend (fragment_cache_prefix = "" , fragment_cache = None )
14+
15+ def parse (self , parser ):
16+ # the first token is the token that started the tag. In our case
17+ # we only listen to ``'cache'`` so this will be a name token with
18+ # `cache` as value. We get the line number so that we can give
19+ # that line number to the nodes we create by hand.
20+ lineno = next (parser .stream ).lineno
21+
22+ # now we parse a single expression that is used as cache key.
23+ args = [parser .parse_expression ()]
24+
25+ # if there is a comma, the user provided a timeout. If not use
26+ # None as second parameter.
27+ if parser .stream .skip_if ("comma" ):
28+ args .append (parser .parse_expression ())
29+ else :
30+ args .append (nodes .Const (None ))
31+
32+ # now we parse the body of the cache block up to `endcache` and
33+ # drop the needle (which would always be `endcache` in that case)
34+ body = parser .parse_statements (["name:endcache" ], drop_needle = True )
35+
36+ # now return a `CallBlock` node that calls our _cache_support
37+ # helper method on this extension.
38+ return nodes .CallBlock (
39+ self .call_method ("_cache_support" , args ), [], [], body
40+ ).set_lineno (lineno )
41+
42+ def _cache_support (self , name , timeout , caller ):
43+ """Helper callback."""
44+ key = self .environment .fragment_cache_prefix + name
45+
46+ # try to load the block from the cache
47+ # if there is no fragment in the cache, render it and store
48+ # it in the cache.
49+ rv = self .environment .fragment_cache .get (key )
50+ if rv is not None :
51+ return rv
52+ rv = caller ()
53+ self .environment .fragment_cache .add (key , rv , timeout )
54+ return rv
0 commit comments