Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add env argument to Jinja2Templates, remove **env_options. (ref #2134) #2159

Merged
merged 17 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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.
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this doesn't render very well on mkdocs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks good
image

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok. Great 👍



```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__(
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we overload this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea

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):
Kludex marked this conversation as resolved.
Show resolved Hide resolved
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)