blob: cb30ebe571952eec183d9cce3722af5d9deb5b11 [file] [log] [blame]
Armin Ronacher42549362010-02-09 16:35:08 +01001# -*- coding: utf-8 -*-
2"""
3 jinja2.testsuite.loader
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
6 Test the loaders.
7
Armin Ronacherbbe0a412017-01-07 16:17:14 +01008 :copyright: (c) 2017 by the Jinja Team.
Armin Ronacher42549362010-02-09 16:35:08 +01009 :license: BSD, see LICENSE for more details.
10"""
11import os
Armin Ronacher64b08a02010-03-12 03:17:41 +010012import sys
Armin Ronacher42549362010-02-09 16:35:08 +010013import tempfile
Armin Ronacher12a316b2010-03-12 17:59:51 +010014import shutil
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053015import pytest
pgjones1a610082016-05-21 16:17:21 +010016import weakref
Armin Ronacher42549362010-02-09 16:35:08 +010017
Armin Ronacher42549362010-02-09 16:35:08 +010018from jinja2 import Environment, loaders
Armin Ronacherdec91942013-05-20 12:11:02 +010019from jinja2._compat import PYPY, PY2
Armin Ronacher42549362010-02-09 16:35:08 +010020from jinja2.loaders import split_template_path
21from jinja2.exceptions import TemplateNotFound
22
23
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053024@pytest.mark.loaders
Armin Ronacher73e2b512017-01-06 21:00:01 +010025class TestLoaders(object):
Armin Ronacher42549362010-02-09 16:35:08 +010026
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053027 def test_dict_loader(self, dict_loader):
Armin Ronacher42549362010-02-09 16:35:08 +010028 env = Environment(loader=dict_loader)
29 tmpl = env.get_template('justdict.html')
30 assert tmpl.render().strip() == 'FOO'
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053031 pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
Armin Ronacher42549362010-02-09 16:35:08 +010032
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053033 def test_package_loader(self, package_loader):
Armin Ronacher42549362010-02-09 16:35:08 +010034 env = Environment(loader=package_loader)
35 tmpl = env.get_template('test.html')
36 assert tmpl.render().strip() == 'BAR'
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053037 pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
Armin Ronacher42549362010-02-09 16:35:08 +010038
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053039 def test_filesystem_loader(self, filesystem_loader):
Armin Ronacher42549362010-02-09 16:35:08 +010040 env = Environment(loader=filesystem_loader)
41 tmpl = env.get_template('test.html')
42 assert tmpl.render().strip() == 'BAR'
43 tmpl = env.get_template('foo/test.html')
44 assert tmpl.render().strip() == 'FOO'
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053045 pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
Armin Ronacher42549362010-02-09 16:35:08 +010046
David Lordaaf13a22019-10-13 06:40:54 -070047 def test_filesystem_loader_overlapping_names(self, filesystem_loader):
48 res = os.path.dirname(filesystem_loader.searchpath[0])
49 t2_dir = os.path.join(res, "templates2")
50 # Make "foo" show up before "foo/test.html".
51 filesystem_loader.searchpath.insert(0, t2_dir)
52 e = Environment(loader=filesystem_loader)
53 e.get_template("foo")
54 # This would raise NotADirectoryError if "t2/foo" wasn't skipped.
55 e.get_template("foo/test.html")
56
57
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053058 def test_choice_loader(self, choice_loader):
Armin Ronacher42549362010-02-09 16:35:08 +010059 env = Environment(loader=choice_loader)
60 tmpl = env.get_template('justdict.html')
61 assert tmpl.render().strip() == 'FOO'
62 tmpl = env.get_template('test.html')
63 assert tmpl.render().strip() == 'BAR'
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053064 pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
Armin Ronacher42549362010-02-09 16:35:08 +010065
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053066 def test_function_loader(self, function_loader):
Armin Ronacher42549362010-02-09 16:35:08 +010067 env = Environment(loader=function_loader)
68 tmpl = env.get_template('justfunction.html')
69 assert tmpl.render().strip() == 'FOO'
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053070 pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
Armin Ronacher42549362010-02-09 16:35:08 +010071
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053072 def test_prefix_loader(self, prefix_loader):
Armin Ronacher42549362010-02-09 16:35:08 +010073 env = Environment(loader=prefix_loader)
74 tmpl = env.get_template('a/test.html')
75 assert tmpl.render().strip() == 'BAR'
76 tmpl = env.get_template('b/justdict.html')
77 assert tmpl.render().strip() == 'FOO'
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053078 pytest.raises(TemplateNotFound, env.get_template, 'missing')
Armin Ronacher42549362010-02-09 16:35:08 +010079
80 def test_caching(self):
81 changed = False
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +053082
Armin Ronacher42549362010-02-09 16:35:08 +010083 class TestLoader(loaders.BaseLoader):
84 def get_source(self, environment, template):
85 return u'foo', None, lambda: not changed
86 env = Environment(loader=TestLoader(), cache_size=-1)
87 tmpl = env.get_template('template')
88 assert tmpl is env.get_template('template')
89 changed = True
90 assert tmpl is not env.get_template('template')
91 changed = False
92
pgjones7d8ec0f2016-05-08 16:10:35 +010093 def test_no_cache(self):
94 mapping = {'foo': 'one'}
95 env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
96 assert env.get_template('foo') is not env.get_template('foo')
Armin Ronacher42549362010-02-09 16:35:08 +010097
pgjones7d8ec0f2016-05-08 16:10:35 +010098 def test_limited_size_cache(self):
99 mapping = {'one': 'foo', 'two': 'bar', 'three': 'baz'}
100 loader = loaders.DictLoader(mapping)
101 env = Environment(loader=loader, cache_size=2)
Armin Ronacher42549362010-02-09 16:35:08 +0100102 t1 = env.get_template('one')
103 t2 = env.get_template('two')
104 assert t2 is env.get_template('two')
105 assert t1 is env.get_template('one')
106 t3 = env.get_template('three')
pgjones1a610082016-05-21 16:17:21 +0100107 loader_ref = weakref.ref(loader)
108 assert (loader_ref, 'one') in env.cache
109 assert (loader_ref, 'two') not in env.cache
110 assert (loader_ref, 'three') in env.cache
pgjones7d8ec0f2016-05-08 16:10:35 +0100111
112 def test_cache_loader_change(self):
113 loader1 = loaders.DictLoader({'foo': 'one'})
114 loader2 = loaders.DictLoader({'foo': 'two'})
115 env = Environment(loader=loader1, cache_size=2)
116 assert env.get_template('foo').render() == 'one'
117 env.loader = loader2
118 assert env.get_template('foo').render() == 'two'
Armin Ronacher42549362010-02-09 16:35:08 +0100119
Alex Morega85b9c8a2012-11-18 18:19:47 +0100120 def test_dict_loader_cache_invalidates(self):
121 mapping = {'foo': "one"}
122 env = Environment(loader=loaders.DictLoader(mapping))
123 assert env.get_template('foo').render() == "one"
124 mapping['foo'] = "two"
125 assert env.get_template('foo').render() == "two"
126
Armin Ronacher42549362010-02-09 16:35:08 +0100127 def test_split_template_path(self):
128 assert split_template_path('foo/bar') == ['foo', 'bar']
129 assert split_template_path('./foo/bar') == ['foo', 'bar']
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530130 pytest.raises(TemplateNotFound, split_template_path, '../foo')
Armin Ronacher42549362010-02-09 16:35:08 +0100131
132
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530133@pytest.mark.loaders
134@pytest.mark.moduleloader
Armin Ronacher73e2b512017-01-06 21:00:01 +0100135class TestModuleLoader(object):
Armin Ronacher64b08a02010-03-12 03:17:41 +0100136 archive = None
137
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530138 def compile_down(self, prefix_loader, zip='deflated', py_compile=False):
Armin Ronacher12a316b2010-03-12 17:59:51 +0100139 log = []
Armin Ronacher64b08a02010-03-12 03:17:41 +0100140 self.reg_env = Environment(loader=prefix_loader)
Armin Ronacher12a316b2010-03-12 17:59:51 +0100141 if zip is not None:
Wing6b990c12014-05-17 13:18:39 +0800142 fd, self.archive = tempfile.mkstemp(suffix='.zip')
143 os.close(fd)
Armin Ronacher12a316b2010-03-12 17:59:51 +0100144 else:
145 self.archive = tempfile.mkdtemp()
146 self.reg_env.compile_templates(self.archive, zip=zip,
147 log_function=log.append,
148 py_compile=py_compile)
Armin Ronacher64b08a02010-03-12 03:17:41 +0100149 self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
Armin Ronacher12a316b2010-03-12 17:59:51 +0100150 return ''.join(log)
Armin Ronacher64b08a02010-03-12 03:17:41 +0100151
152 def teardown(self):
Armin Ronacher12a316b2010-03-12 17:59:51 +0100153 if hasattr(self, 'mod_env'):
154 if os.path.isfile(self.archive):
155 os.remove(self.archive)
156 else:
157 shutil.rmtree(self.archive)
158 self.archive = None
Armin Ronacher64b08a02010-03-12 03:17:41 +0100159
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530160 def test_log(self, prefix_loader):
161 log = self.compile_down(prefix_loader)
Armin Ronacher12a316b2010-03-12 17:59:51 +0100162 assert 'Compiled "a/foo/test.html" as ' \
163 'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log
164 assert 'Finished compiling templates' in log
165 assert 'Could not compile "a/syntaxerror.html": ' \
166 'Encountered unknown tag \'endif\'' in log
167
168 def _test_common(self):
Armin Ronacher64b08a02010-03-12 03:17:41 +0100169 tmpl1 = self.reg_env.get_template('a/test.html')
170 tmpl2 = self.mod_env.get_template('a/test.html')
171 assert tmpl1.render() == tmpl2.render()
172
173 tmpl1 = self.reg_env.get_template('b/justdict.html')
174 tmpl2 = self.mod_env.get_template('b/justdict.html')
175 assert tmpl1.render() == tmpl2.render()
176
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530177 def test_deflated_zip_compile(self, prefix_loader):
178 self.compile_down(prefix_loader, zip='deflated')
Armin Ronacher12a316b2010-03-12 17:59:51 +0100179 self._test_common()
180
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530181 def test_stored_zip_compile(self, prefix_loader):
182 self.compile_down(prefix_loader, zip='stored')
Armin Ronacher12a316b2010-03-12 17:59:51 +0100183 self._test_common()
184
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530185 def test_filesystem_compile(self, prefix_loader):
186 self.compile_down(prefix_loader, zip=None)
Armin Ronacher12a316b2010-03-12 17:59:51 +0100187 self._test_common()
188
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530189 def test_weak_references(self, prefix_loader):
190 self.compile_down(prefix_loader)
Armin Ronacher64b08a02010-03-12 03:17:41 +0100191 tmpl = self.mod_env.get_template('a/test.html')
192 key = loaders.ModuleLoader.get_template_key('a/test.html')
193 name = self.mod_env.loader.module.__name__
194
195 assert hasattr(self.mod_env.loader.module, key)
196 assert name in sys.modules
197
198 # unset all, ensure the module is gone from sys.modules
199 self.mod_env = tmpl = None
Armin Ronacher95131f22010-03-12 03:37:03 +0100200
201 try:
202 import gc
203 gc.collect()
204 except:
205 pass
206
Armin Ronacher64b08a02010-03-12 03:17:41 +0100207 assert name not in sys.modules
208
Armin Ronacherdec91942013-05-20 12:11:02 +0100209 # This test only makes sense on non-pypy python 2
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530210 @pytest.mark.skipif(
211 not (PY2 and not PYPY),
212 reason='This test only makes sense on non-pypy python 2')
213 def test_byte_compilation(self, prefix_loader):
214 log = self.compile_down(prefix_loader, py_compile=True)
215 assert 'Byte-compiled "a/test.html"' in log
216 tmpl1 = self.mod_env.get_template('a/test.html')
217 mod = self.mod_env.loader.module. \
218 tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
219 assert mod.__file__.endswith('.pyc')
Armin Ronacher12a316b2010-03-12 17:59:51 +0100220
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530221 def test_choice_loader(self, prefix_loader):
222 log = self.compile_down(prefix_loader)
Armin Ronacher6fa6cb02011-09-13 23:27:41 +0200223
224 self.mod_env.loader = loaders.ChoiceLoader([
225 self.mod_env.loader,
226 loaders.DictLoader({'DICT_SOURCE': 'DICT_TEMPLATE'})
227 ])
228
229 tmpl1 = self.mod_env.get_template('a/test.html')
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530230 assert tmpl1.render() == 'BAR'
Armin Ronacher6fa6cb02011-09-13 23:27:41 +0200231 tmpl2 = self.mod_env.get_template('DICT_SOURCE')
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530232 assert tmpl2.render() == 'DICT_TEMPLATE'
Armin Ronacher6fa6cb02011-09-13 23:27:41 +0200233
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530234 def test_prefix_loader(self, prefix_loader):
235 log = self.compile_down(prefix_loader)
Armin Ronacher6fa6cb02011-09-13 23:27:41 +0200236
237 self.mod_env.loader = loaders.PrefixLoader({
238 'MOD': self.mod_env.loader,
239 'DICT': loaders.DictLoader({'test.html': 'DICT_TEMPLATE'})
240 })
241
242 tmpl1 = self.mod_env.get_template('MOD/a/test.html')
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530243 assert tmpl1.render() == 'BAR'
Armin Ronacher6fa6cb02011-09-13 23:27:41 +0200244 tmpl2 = self.mod_env.get_template('DICT/test.html')
Kartheek Lenkala9d4afa12015-03-22 15:28:54 +0530245 assert tmpl2.render() == 'DICT_TEMPLATE'