Skip to content

Commit

Permalink
Add env argument to Jinja2Templates, deprecate **env_options. (ref #2134
Browse files Browse the repository at this point in the history
) (#2159)

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
  • Loading branch information
alex-oleshkevich and Kludex committed Jun 5, 2023
1 parent fe1a9d8 commit d155d3b
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
15 changes: 15 additions & 0 deletions docs/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
43 changes: 41 additions & 2 deletions starlette/templating.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typing
import warnings
from os import PathLike

from starlette.background import BackgroundTask
Expand Down Expand Up @@ -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,
Expand Down
34 changes: 34 additions & 0 deletions tests/test_templates.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
from pathlib import Path

import jinja2
import pytest

from starlette.applications import Starlette
Expand Down Expand Up @@ -124,3 +125,36 @@ async def page_b(request):
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)

0 comments on commit d155d3b

Please sign in to comment.