Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | """ |
| 3 | jinja2.testsuite.loader |
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~ |
| 5 | |
| 6 | Test the loaders. |
| 7 | |
Armin Ronacher | bbe0a41 | 2017-01-07 16:17:14 +0100 | [diff] [blame] | 8 | :copyright: (c) 2017 by the Jinja Team. |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 9 | :license: BSD, see LICENSE for more details. |
| 10 | """ |
| 11 | import os |
Armin Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 12 | import sys |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 13 | import tempfile |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 14 | import shutil |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 15 | import pytest |
pgjones | 1a61008 | 2016-05-21 16:17:21 +0100 | [diff] [blame] | 16 | import weakref |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 17 | |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 18 | from jinja2 import Environment, loaders |
Armin Ronacher | dec9194 | 2013-05-20 12:11:02 +0100 | [diff] [blame] | 19 | from jinja2._compat import PYPY, PY2 |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 20 | from jinja2.loaders import split_template_path |
| 21 | from jinja2.exceptions import TemplateNotFound |
| 22 | |
| 23 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 24 | @pytest.mark.loaders |
Armin Ronacher | 73e2b51 | 2017-01-06 21:00:01 +0100 | [diff] [blame] | 25 | class TestLoaders(object): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 26 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 27 | def test_dict_loader(self, dict_loader): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 28 | env = Environment(loader=dict_loader) |
| 29 | tmpl = env.get_template('justdict.html') |
| 30 | assert tmpl.render().strip() == 'FOO' |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 31 | pytest.raises(TemplateNotFound, env.get_template, 'missing.html') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 32 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 33 | def test_package_loader(self, package_loader): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 34 | env = Environment(loader=package_loader) |
| 35 | tmpl = env.get_template('test.html') |
| 36 | assert tmpl.render().strip() == 'BAR' |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 37 | pytest.raises(TemplateNotFound, env.get_template, 'missing.html') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 38 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 39 | def test_filesystem_loader(self, filesystem_loader): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 40 | 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 45 | pytest.raises(TemplateNotFound, env.get_template, 'missing.html') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 46 | |
David Lord | aaf13a2 | 2019-10-13 06:40:54 -0700 | [diff] [blame^] | 47 | 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 58 | def test_choice_loader(self, choice_loader): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 59 | 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 64 | pytest.raises(TemplateNotFound, env.get_template, 'missing.html') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 65 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 66 | def test_function_loader(self, function_loader): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 67 | env = Environment(loader=function_loader) |
| 68 | tmpl = env.get_template('justfunction.html') |
| 69 | assert tmpl.render().strip() == 'FOO' |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 70 | pytest.raises(TemplateNotFound, env.get_template, 'missing.html') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 71 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 72 | def test_prefix_loader(self, prefix_loader): |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 73 | 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 78 | pytest.raises(TemplateNotFound, env.get_template, 'missing') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 79 | |
| 80 | def test_caching(self): |
| 81 | changed = False |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 82 | |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 83 | 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 | |
pgjones | 7d8ec0f | 2016-05-08 16:10:35 +0100 | [diff] [blame] | 93 | 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 Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 97 | |
pgjones | 7d8ec0f | 2016-05-08 16:10:35 +0100 | [diff] [blame] | 98 | 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 Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 102 | 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') |
pgjones | 1a61008 | 2016-05-21 16:17:21 +0100 | [diff] [blame] | 107 | 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 |
pgjones | 7d8ec0f | 2016-05-08 16:10:35 +0100 | [diff] [blame] | 111 | |
| 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 Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 119 | |
Alex Morega | 85b9c8a | 2012-11-18 18:19:47 +0100 | [diff] [blame] | 120 | 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 Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 127 | 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 130 | pytest.raises(TemplateNotFound, split_template_path, '../foo') |
Armin Ronacher | 4254936 | 2010-02-09 16:35:08 +0100 | [diff] [blame] | 131 | |
| 132 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 133 | @pytest.mark.loaders |
| 134 | @pytest.mark.moduleloader |
Armin Ronacher | 73e2b51 | 2017-01-06 21:00:01 +0100 | [diff] [blame] | 135 | class TestModuleLoader(object): |
Armin Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 136 | archive = None |
| 137 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 138 | def compile_down(self, prefix_loader, zip='deflated', py_compile=False): |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 139 | log = [] |
Armin Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 140 | self.reg_env = Environment(loader=prefix_loader) |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 141 | if zip is not None: |
Wing | 6b990c1 | 2014-05-17 13:18:39 +0800 | [diff] [blame] | 142 | fd, self.archive = tempfile.mkstemp(suffix='.zip') |
| 143 | os.close(fd) |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 144 | 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 Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 149 | self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive)) |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 150 | return ''.join(log) |
Armin Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 151 | |
| 152 | def teardown(self): |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 153 | 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 Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 159 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 160 | def test_log(self, prefix_loader): |
| 161 | log = self.compile_down(prefix_loader) |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 162 | 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 Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 169 | 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 177 | def test_deflated_zip_compile(self, prefix_loader): |
| 178 | self.compile_down(prefix_loader, zip='deflated') |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 179 | self._test_common() |
| 180 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 181 | def test_stored_zip_compile(self, prefix_loader): |
| 182 | self.compile_down(prefix_loader, zip='stored') |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 183 | self._test_common() |
| 184 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 185 | def test_filesystem_compile(self, prefix_loader): |
| 186 | self.compile_down(prefix_loader, zip=None) |
Armin Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 187 | self._test_common() |
| 188 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 189 | def test_weak_references(self, prefix_loader): |
| 190 | self.compile_down(prefix_loader) |
Armin Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 191 | 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 Ronacher | 95131f2 | 2010-03-12 03:37:03 +0100 | [diff] [blame] | 200 | |
| 201 | try: |
| 202 | import gc |
| 203 | gc.collect() |
| 204 | except: |
| 205 | pass |
| 206 | |
Armin Ronacher | 64b08a0 | 2010-03-12 03:17:41 +0100 | [diff] [blame] | 207 | assert name not in sys.modules |
| 208 | |
Armin Ronacher | dec9194 | 2013-05-20 12:11:02 +0100 | [diff] [blame] | 209 | # This test only makes sense on non-pypy python 2 |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 210 | @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 Ronacher | 12a316b | 2010-03-12 17:59:51 +0100 | [diff] [blame] | 220 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 221 | def test_choice_loader(self, prefix_loader): |
| 222 | log = self.compile_down(prefix_loader) |
Armin Ronacher | 6fa6cb0 | 2011-09-13 23:27:41 +0200 | [diff] [blame] | 223 | |
| 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 230 | assert tmpl1.render() == 'BAR' |
Armin Ronacher | 6fa6cb0 | 2011-09-13 23:27:41 +0200 | [diff] [blame] | 231 | tmpl2 = self.mod_env.get_template('DICT_SOURCE') |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 232 | assert tmpl2.render() == 'DICT_TEMPLATE' |
Armin Ronacher | 6fa6cb0 | 2011-09-13 23:27:41 +0200 | [diff] [blame] | 233 | |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 234 | def test_prefix_loader(self, prefix_loader): |
| 235 | log = self.compile_down(prefix_loader) |
Armin Ronacher | 6fa6cb0 | 2011-09-13 23:27:41 +0200 | [diff] [blame] | 236 | |
| 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 Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 243 | assert tmpl1.render() == 'BAR' |
Armin Ronacher | 6fa6cb0 | 2011-09-13 23:27:41 +0200 | [diff] [blame] | 244 | tmpl2 = self.mod_env.get_template('DICT/test.html') |
Kartheek Lenkala | 9d4afa1 | 2015-03-22 15:28:54 +0530 | [diff] [blame] | 245 | assert tmpl2.render() == 'DICT_TEMPLATE' |