summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2021-08-09 11:00:30 -0700
committerGitHub <noreply@github.com>2021-08-09 11:00:30 -0700
commit189132094135d4c84414404c3b388500d35dc49e (patch)
treebfc87bd8ed3e8c04f3efe3c755c205f7c2a86665
parent02071b3e5933560f070e3a898f8aa82622d2001e (diff)
parent4c703ec44dc74b25ba4f1fb7b87bf9106313ffcf (diff)
downloadjinja2-189132094135d4c84414404c3b388500d35dc49e.tar.gz
Merge pull request #1454 from atetubou/deterministic_test
make compile_templates deterministic
-rw-r--r--CHANGES.rst2
-rw-r--r--src/jinja2/compiler.py2
-rw-r--r--src/jinja2/idtracking.py2
-rw-r--r--tests/test_compile.py28
4 files changed, 32 insertions, 2 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 7bfebff..116461a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -7,6 +7,8 @@ Unreleased
- Fix a loop scoping bug that caused assignments in nested loops
to still be referenced outside of it. :issue:`1427`
+- Make ``compile_templates`` deterministic for filter and import
+ names. :issue:`1452, 1453`
Version 3.0.1
diff --git a/src/jinja2/compiler.py b/src/jinja2/compiler.py
index 5fe9349..b629720 100644
--- a/src/jinja2/compiler.py
+++ b/src/jinja2/compiler.py
@@ -556,7 +556,7 @@ class CodeGenerator(NodeVisitor):
visitor.tests,
"tests",
):
- for name in names:
+ for name in sorted(names):
if name not in id_map:
id_map[name] = self.temporary_identifier()
diff --git a/src/jinja2/idtracking.py b/src/jinja2/idtracking.py
index a2e7a05..38c525e 100644
--- a/src/jinja2/idtracking.py
+++ b/src/jinja2/idtracking.py
@@ -149,7 +149,7 @@ class Symbols:
node: t.Optional["Symbols"] = self
while node is not None:
- for name in node.stores:
+ for name in sorted(node.stores):
if name not in rv:
rv[name] = self.find_ref(name) # type: ignore
diff --git a/tests/test_compile.py b/tests/test_compile.py
new file mode 100644
index 0000000..42a773f
--- /dev/null
+++ b/tests/test_compile.py
@@ -0,0 +1,28 @@
+import os
+import re
+
+from jinja2.environment import Environment
+from jinja2.loaders import DictLoader
+
+
+def test_filters_deterministic(tmp_path):
+ src = "".join(f"{{{{ {i}|filter{i} }}}}" for i in range(10))
+ env = Environment(loader=DictLoader({"foo": src}))
+ env.filters.update(dict.fromkeys((f"filter{i}" for i in range(10)), lambda: None))
+ env.compile_templates(tmp_path, zip=None)
+ name = os.listdir(tmp_path)[0]
+ content = (tmp_path / name).read_text("utf8")
+ expect = [f"filters['filter{i}']" for i in range(10)]
+ found = re.findall(r"filters\['filter\d']", content)
+ assert found == expect
+
+
+def test_import_as_with_context_deterministic(tmp_path):
+ src = "\n".join(f'{{% import "bar" as bar{i} with context %}}' for i in range(10))
+ env = Environment(loader=DictLoader({"foo": src}))
+ env.compile_templates(tmp_path, zip=None)
+ name = os.listdir(tmp_path)[0]
+ content = (tmp_path / name).read_text("utf8")
+ expect = [f"'bar{i}': " for i in range(10)]
+ found = re.findall(r"'bar\d': ", content)[:10]
+ assert found == expect