]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
Change cache key definitiion in environment 583/head
authorpgjones <philip.graham.jones@googlemail.com>
Sun, 8 May 2016 15:10:35 +0000 (16:10 +0100)
committerpgjones <philip.graham.jones@googlemail.com>
Thu, 19 May 2016 18:42:16 +0000 (19:42 +0100)
In 6671b973e6de5abc46829a27fd3bbb989d68ca3a the load_template method
was altered to use a cache key other than the template name. The key
chosen was the abs path as returned from the loader get_source
method. Unless there is no path in which case the name is
used. Unfortunately this introduced a performance regression, #485, as
the get_source method (in the FileStoreLoader) loads the template
(causing IO).

The purpose of #332 was to allow the loader to change whilst ensuring
the correct template was loaded, i.e. to fix this case

    env.loader = loader1
    env.get_template('index.html') # return loader1/index.html
    env.loader = loader2
    env.get_template('index.html') # also return loader1/index.html because of cache

This commit changes the cache key to be a tuple of the id(loader) and
the template name. Therefore fixing the above case without calling the
get_source method and thereby avoiding the IO load.

A test has been added to ensure the above case works as expected, this
required a minor refactor of the caching tests.

jinja2/environment.py
tests/test_loader.py

index 6d8c17d4674fcdc926dc2b68ca1fed7dc16933ca..67d05dd976db99bde8b9b54dcd1d9b034624cb5e 100644 (file)
@@ -769,15 +769,7 @@ class Environment(object):
     def _load_template(self, name, globals):
         if self.loader is None:
             raise TypeError('no loader for this environment specified')
-        try:
-            # use abs path for cache key
-            cache_key = self.loader.get_source(self, name)[1]
-        except RuntimeError:
-            # if loader does not implement get_source()
-            cache_key = None
-        # if template is not file, use name for cache key
-        if cache_key is None:
-            cache_key = name
+        cache_key = (id(self.loader), name)
         if self.cache is not None:
             template = self.cache.get(cache_key)
             if template is not None and (not self.auto_reload or
index 6d22fad390cb801a43bed521caf7e752c568a1c8..6b9d9bb4f4123538fabce08573bb9ed8ff783e1d 100644 (file)
@@ -78,19 +78,31 @@ class TestLoaders():
         assert tmpl is not env.get_template('template')
         changed = False
 
-        env = Environment(loader=TestLoader(), cache_size=0)
-        assert env.get_template('template') \
-            is not env.get_template('template')
-
-        env = Environment(loader=TestLoader(), cache_size=2)
+    def test_no_cache(self):
+        mapping = {'foo': 'one'}
+        env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
+        assert env.get_template('foo') is not env.get_template('foo')
+
+    def test_limited_size_cache(self):
+        mapping = {'one': 'foo', 'two': 'bar', 'three': 'baz'}
+        loader = loaders.DictLoader(mapping)
+        env = Environment(loader=loader, cache_size=2)
         t1 = env.get_template('one')
         t2 = env.get_template('two')
         assert t2 is env.get_template('two')
         assert t1 is env.get_template('one')
         t3 = env.get_template('three')
-        assert 'one' in env.cache
-        assert 'two' not in env.cache
-        assert 'three' in env.cache
+        assert (id(loader), 'one') in env.cache
+        assert (id(loader), 'two') not in env.cache
+        assert (id(loader), 'three') in env.cache
+
+    def test_cache_loader_change(self):
+        loader1 = loaders.DictLoader({'foo': 'one'})
+        loader2 = loaders.DictLoader({'foo': 'two'})
+        env = Environment(loader=loader1, cache_size=2)
+        assert env.get_template('foo').render() == 'one'
+        env.loader = loader2
+        assert env.get_template('foo').render() == 'two'
 
     def test_dict_loader_cache_invalidates(self):
         mapping = {'foo': "one"}