diff --git a/docs/templates.md b/docs/templates.md
index 749c7a8c2..66f2f9ca1 100644
--- a/docs/templates.md
+++ b/docs/templates.md
@@ -1,6 +1,14 @@
Starlette is not _strictly_ coupled to any particular templating engine, but
Jinja2 provides an excellent choice.
+### Jinja2Templates
+
+Signature: `Jinja2Templates(directory, context_processors=None, **env_options)`
+
+* `directory` - A string, [os.Pathlike][pathlike] or a list of strings or [os.Pathlike][pathlike] denoting a directory path.
+* `context_processors` - A list of functions that return a dictionary to add to the template context.
+* `**env_options` - Additional keyword arguments to pass to the Jinja2 environment.
+
Starlette provides a simple way to get `jinja2` configured. This is probably
what you want to use by default.
@@ -128,3 +136,4 @@ for example, strictly evaluate any database queries within the view and
include the final results in the context.
[jinja2]: https://jinja.palletsprojects.com/en/3.0.x/api/?highlight=environment#writing-filters
+[pathlike]: https://docs.python.org/3/library/os.html#os.PathLike
diff --git a/starlette/templating.py b/starlette/templating.py
index 7df8f6d29..f5da207bd 100644
--- a/starlette/templating.py
+++ b/starlette/templating.py
@@ -64,7 +64,9 @@ class Jinja2Templates:
def __init__(
self,
- directory: typing.Union[str, PathLike],
+ directory: typing.Union[
+ str, PathLike, typing.Sequence[typing.Union[str, PathLike]]
+ ],
context_processors: typing.Optional[
typing.List[typing.Callable[[Request], typing.Dict[str, typing.Any]]]
] = None,
@@ -75,7 +77,11 @@ def __init__(
self.context_processors = context_processors or []
def _create_env(
- self, directory: typing.Union[str, PathLike], **env_options: typing.Any
+ self,
+ directory: typing.Union[
+ str, PathLike, typing.Sequence[typing.Union[str, PathLike]]
+ ],
+ **env_options: typing.Any,
) -> "jinja2.Environment":
@pass_context
def url_for(context: dict, name: str, **path_params: typing.Any) -> URL:
diff --git a/tests/test_templates.py b/tests/test_templates.py
index 2d918f7d0..527872666 100644
--- a/tests/test_templates.py
+++ b/tests/test_templates.py
@@ -1,4 +1,5 @@
import os
+from pathlib import Path
import pytest
@@ -88,3 +89,38 @@ async def dispatch(self, request, call_next):
assert response.text == "Hello, world"
assert response.template.name == "index.html"
assert set(response.context.keys()) == {"request"}
+
+
+def test_templates_with_directories(tmp_path: Path, test_client_factory):
+ dir_a = tmp_path.resolve() / "a"
+ dir_a.mkdir()
+ template_a = dir_a / "template_a.html"
+ template_a.write_text(" a")
+
+ async def page_a(request):
+ return templates.TemplateResponse("template_a.html", {"request": request})
+
+ dir_b = tmp_path.resolve() / "b"
+ dir_b.mkdir()
+ template_b = dir_b / "template_b.html"
+ template_b.write_text(" b")
+
+ async def page_b(request):
+ return templates.TemplateResponse("template_b.html", {"request": request})
+
+ app = Starlette(
+ debug=True,
+ routes=[Route("/a", endpoint=page_a), Route("/b", endpoint=page_b)],
+ )
+ templates = Jinja2Templates(directory=[dir_a, dir_b])
+
+ client = test_client_factory(app)
+ response = client.get("/a")
+ assert response.text == " a"
+ assert response.template.name == "template_a.html"
+ assert set(response.context.keys()) == {"request"}
+
+ response = client.get("/b")
+ assert response.text == " b"
+ assert response.template.name == "template_b.html"
+ assert set(response.context.keys()) == {"request"}