Skip to content

Commit cc9bcec

Browse files
committed
feat: cache for jinja
1 parent 16f9fe5 commit cc9bcec

3 files changed

Lines changed: 61 additions & 3 deletions

File tree

mapbuilder/builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def __init__(self, source_dir, target_dir, cache_dir, config):
8686
else:
8787
logging.error(f"Unknown data source type for data source {data_source}")
8888

89-
self.jinja_handler = JinjaHandler(self.data, self.config)
89+
self.jinja_handler = JinjaHandler(self.data, self.config, cache_dir)
9090

9191
def __load(self, name: str, src: str):
9292
if src.startswith("dfs:"):

mapbuilder/handlers/jinja.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import numpy as np
55
import shapely
66
import shapely.ops
7+
from cachelib import FileSystemCache
78
from jinja2 import Environment, FileSystemLoader
89
from more_itertools import unique_everseen
910
from shapely import Geometry, Polygon
@@ -12,17 +13,20 @@
1213
from mapbuilder.utils.ad import render_cl, render_runways
1314
from mapbuilder.utils.ecl import draw_ecl_dashes, draw_loc_tick, draw_marker_ticks
1415
from mapbuilder.utils.geo import brg, fix
16+
from mapbuilder.utils.jinja_fragment_cache import FragmentCacheExtension
1517
from mapbuilder.utils.sidstar import render_sid
1618

1719

1820
class JinjaHandler:
19-
def __init__(self, data, config):
21+
def __init__(self, data, config, cache_dir):
2022
self.data = data
2123
self.config = config
24+
self.cache_dir = cache_dir
2225

2326
def handle(self, item: Path) -> str:
2427
file_loader = FileSystemLoader(item.parent)
25-
jinja_env = Environment(loader=file_loader)
28+
jinja_env = Environment(loader=file_loader, extensions=[FragmentCacheExtension])
29+
jinja_env.fragment_cache = FileSystemCache(self.cache_dir)
2630
jinja_env.globals.update(
2731
data=self.data,
2832
runways=self.config["runways"],
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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

Comments
 (0)