]> git.ipfire.org Git - thirdparty/starlette.git/commitdiff
Add env argument to Jinja2Templates, deprecate **env_options. (ref #2134) (#2159)
authorAlex Oleshkevich <alex.oleshkevich@gmail.com>
Mon, 5 Jun 2023 18:20:36 +0000 (20:20 +0200)
committerGitHub <noreply@github.com>
Mon, 5 Jun 2023 18:20:36 +0000 (12:20 -0600)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
docs/templates.md
starlette/templating.py
tests/test_templates.py

index 66f2f9ca1d2464609a8290d40512f1966fa15200..ba9c4255b545c1c4827a49ca5eac45c6f1ec1cc4 100644 (file)
@@ -58,6 +58,21 @@ templates = Jinja2Templates(directory='templates')
 templates.env.filters['marked'] = marked_filter
 ```
 
+
+## Using custom jinja2.Environment instance
+
+Starlette also accepts a preconfigured [`jinja2.Environment`](https://jinja.palletsprojects.com/en/3.0.x/api/#api) instance. 
+
+
+```python
+import jinja2
+from starlette.templating import Jinja2Templates
+
+env = jinja2.Environment(...)
+templates = Jinja2Templates(env=env)
+```
+
+
 ## Context processors
 
 A context processor is a function that returns a dictionary to be merged into a template context.
index b9421cc678373eca8cae7ada5d81d130aa376215..ec9ca193dcad95379543a67bd97549717e5a05d4 100644 (file)
@@ -1,4 +1,5 @@
 import typing
+import warnings
 from os import PathLike
 
 from starlette.background import BackgroundTask
@@ -62,19 +63,57 @@ class Jinja2Templates:
     return templates.TemplateResponse("index.html", {"request": request})
     """
 
+    @typing.overload
     def __init__(
         self,
         directory: typing.Union[
-            str, PathLike, typing.Sequence[typing.Union[str, PathLike]]
+            str,
+            PathLike,
+            typing.Sequence[typing.Union[str, PathLike]],
         ],
+        *,
         context_processors: typing.Optional[
             typing.List[typing.Callable[[Request], typing.Dict[str, typing.Any]]]
         ] = None,
         **env_options: typing.Any,
     ) -> None:
+        ...
+
+    @typing.overload
+    def __init__(
+        self,
+        *,
+        env: "jinja2.Environment",
+        context_processors: typing.Optional[
+            typing.List[typing.Callable[[Request], typing.Dict[str, typing.Any]]]
+        ] = None,
+    ) -> None:
+        ...
+
+    def __init__(
+        self,
+        directory: typing.Union[
+            str, PathLike, typing.Sequence[typing.Union[str, PathLike]], None
+        ] = None,
+        *,
+        context_processors: typing.Optional[
+            typing.List[typing.Callable[[Request], typing.Dict[str, typing.Any]]]
+        ] = None,
+        env: typing.Optional["jinja2.Environment"] = None,
+        **env_options: typing.Any,
+    ) -> None:
+        if env_options:
+            warnings.warn(
+                "Extra environment options are deprecated. Use a preconfigured jinja2.Environment instead.",  # noqa: E501
+                DeprecationWarning,
+            )
         assert jinja2 is not None, "jinja2 must be installed to use Jinja2Templates"
-        self.env = self._create_env(directory, **env_options)
+        assert directory or env, "either 'directory' or 'env' arguments must be passed"
         self.context_processors = context_processors or []
+        if directory is not None:
+            self.env = self._create_env(directory, **env_options)
+        elif env is not None:
+            self.env = env
 
     def _create_env(
         self,
index 5278726668368493c9a92006d96dc44dcff4f3a6..1f1909f4b94234430a457173d639b62e4aa73009 100644 (file)
@@ -1,6 +1,7 @@
 import os
 from pathlib import Path
 
+import jinja2
 import pytest
 
 from starlette.applications import Starlette
@@ -124,3 +125,36 @@ def test_templates_with_directories(tmp_path: Path, test_client_factory):
     assert response.text == "<html><a href='http://testserver/b'></a> b</html>"
     assert response.template.name == "template_b.html"
     assert set(response.context.keys()) == {"request"}
+
+
+def test_templates_require_directory_or_environment():
+    with pytest.raises(
+        AssertionError, match="either 'directory' or 'env' arguments must be passed"
+    ):
+        Jinja2Templates()  # type: ignore[call-overload]
+
+
+def test_templates_with_directory(tmpdir):
+    path = os.path.join(tmpdir, "index.html")
+    with open(path, "w") as file:
+        file.write("Hello")
+
+    templates = Jinja2Templates(directory=str(tmpdir))
+    template = templates.get_template("index.html")
+    assert template.render({}) == "Hello"
+
+
+def test_templates_with_environment(tmpdir):
+    path = os.path.join(tmpdir, "index.html")
+    with open(path, "w") as file:
+        file.write("Hello")
+
+    env = jinja2.Environment(loader=jinja2.FileSystemLoader(str(tmpdir)))
+    templates = Jinja2Templates(env=env)
+    template = templates.get_template("index.html")
+    assert template.render({}) == "Hello"
+
+
+def test_templates_with_environment_options_emit_warning(tmpdir):
+    with pytest.warns(DeprecationWarning):
+        Jinja2Templates(str(tmpdir), autoescape=True)