Repository: pallets/jinja (python)

Issue:
f-string sytax error when importing macro in a template which filename is also a template
With this template structure:
```
/templates/
+- {% jinja expr %}.jinja
+- macro_file.jina
```
When `{% jinja expr %}.jinja` imports a macro using 'from "macro_file.jinja" import my_macro' syntax, Environment.render fails with `SyntaxError: f-string: invalid syntax` error message.

Internally jinja concatenates the importing template filename into an f-string, which results with invalid f-string:
```python
if l_0_print_helo is missing:
        l_0_print_helo = undefined(f"the template {included_template.__name__!r} (imported on line 1 in '{% if True %}a{%endif%}.txt.jinja') does not export the requested name 'print_helo'", name='print_helo')
```

Couldn't reproduce the error using `import "macro_file.jinja" as m` syntax.

Environment:

- Python 3.10.7
- Jinja 3.1.2


Pull request description:
fix f-string syntax error in code generation
I've fixed a bug that caused an f-string syntax error in the template compilation when a template, that imports a macro, contains curly braces in its name. The bug was caused by the code-generation of an f-string in which the template name is inserted, and when the template name contains curly braces and the generated code gets executed, Python treats the curly braces as f-string braces. I've changed the code-generation to construct the string differently, such that the affected substring is not an f-string. Instead, the different substrings are concatenated using the `+` operator.

<!--
Link to relevant issues or previous PRs, one per line. Use "fixes" to automatically close an issue.
-->

- fixes #1792

<!--
Ensure each step in CONTRIBUTING.rst is complete by adding an "x" to each box below.

If only docs were changed, these aren't relevant and can be removed.
-->

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [ ] Add or update relevant docs, in the docs folder and in code.
- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [ ] Add `.. versionchanged::` entries in any relevant code docs.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 0a569475..5d64b267 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,6 +8,9 @@ Unreleased
 -   The sandboxed environment handles indirect calls to ``str.format``, such as
     by passing a stored reference to a filter that calls its argument.
     :ghsa:`q2x7-8rv6-6q7h`
+-   Escape template name before formatting it into error messages, to avoid
+    issues with names that contain f-string syntax.
+    :issue:`1792`, :ghsa:`gmj6-6f8f-6699`
 -   Sandbox does not allow ``clear`` and ``pop`` on known mutable sequence
     types. :issue:`2032`
 -   Calling sync ``render`` for an async template uses ``asyncio.run``.
diff --git a/src/jinja2/compiler.py b/src/jinja2/compiler.py
index 074e9b18..23295ec1 100644
--- a/src/jinja2/compiler.py
+++ b/src/jinja2/compiler.py
@@ -1141,9 +1141,14 @@ class CodeGenerator(NodeVisitor):
             )
             self.writeline(f"if {frame.symbols.ref(alias)} is missing:")
             self.indent()
+            # The position will contain the template name, and will be formatted
+            # into a string that will be compiled into an f-string. Curly braces
+            # in the name must be replaced with escapes so that they will not be
+            # executed as part of the f-string.
+            position = self.position(node).replace("{", "{{").replace("}", "}}")
             message = (
                 "the template {included_template.__name__!r}"
-                f" (imported on {self.position(node)})"
+                f" (imported on {position})"
                 f" does not export the requested name {name!r}"
             )
             self.writeline(


Test patch:
diff --git a/tests/test_compile.py b/tests/test_compile.py
index 42efa59c..e1a5391e 100644
--- a/tests/test_compile.py
+++ b/tests/test_compile.py
@@ -1,6 +1,9 @@
 import os
 import re
 
+import pytest
+
+from jinja2 import UndefinedError
 from jinja2.environment import Environment
 from jinja2.loaders import DictLoader
 
@@ -87,3 +90,19 @@ def test_block_set_vars_unpacking_deterministic(tmp_path):
         content,
     )[:10]
     assert found == expect
+
+
+def test_undefined_import_curly_name():
+    env = Environment(
+        loader=DictLoader(
+            {
+                "{bad}": "{% from 'macro' import m %}{{ m() }}",
+                "macro": "",
+            }
+        )
+    )
+
+    # Must not raise `NameError: 'bad' is not defined`, as that would indicate
+    # that `{bad}` is being interpreted as an f-string. It must be escaped.
+    with pytest.raises(UndefinedError):
+        env.get_template("{bad}").render()