Skip to content

Commit 1d3b071

Browse files
authored
Make from_string() and get_template() return backend-specific template (#2400)
* Annotate `context` argument of `make_context()` The implementation of `make_context()` explicitly rejects everything other than `dict` or `None` by raising `TypeError`. * Drop `Context` from allowed types of template render method [DEP 182](https://github.com/django/deps/blob/main/final/0182-multiple-template-engines.rst#backends-api) states: "If `context` is provided, it must be a `dict`.". While the `Jinja2` and `TemplateStrings` backends support arbitrary mappings, `DjangoTemplates` calls `make_context()`, which only supports `dict` (and `None`). * Do not require template render method to return a `SafeString` Only the Django Template Language backend outputs `SafeString`. * Provide arguments types for Jinja2 template render method All of the argument types are Django types, so there is no need to avoid annotating them. Only the Jinja2 native template type is unknown to us. * Allow non-string values in dummy template render context The implementation of the `render()` method uses the standard library method `string.Template.safe_substitute()` to do the actual formatting, which accepts other value types than `str` and simply calls `__str__()` on them. The `safe_substitute()` method is annotated in typeshed with `object` as the value type for the mapping. However, as `_EngineTemplate` uses `Any` instead, I went with that. * Make it explicit that the dummy template class adheres to the protocol * Make `from_string()` and `get_template()` return backend-specific template * Revert "Make it explicit that the dummy template class adheres to the protocol" This reverts commit 509e368. Inheriting from both `string.Template` and `typing.Protocol` causes mypy to report a metaclass conflict on Python 3.8.
1 parent 1d30114 commit 1d3b071

File tree

5 files changed

+12
-7
lines changed

5 files changed

+12
-7
lines changed

django-stubs/template/backends/base.pyi

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ from collections.abc import Iterator, Mapping
22
from typing import Any, Protocol, type_check_only
33

44
from django.http.request import HttpRequest
5-
from django.template.base import Context
65
from django.utils.functional import cached_property
7-
from django.utils.safestring import SafeString
86

97
class BaseEngine:
108
name: str
@@ -23,6 +21,6 @@ class BaseEngine:
2321
class _EngineTemplate(Protocol):
2422
def render(
2523
self,
26-
context: Context | dict[str, Any] | None = ...,
24+
context: dict[str, Any] | None = ...,
2725
request: HttpRequest | None = ...,
28-
) -> SafeString: ...
26+
) -> str: ...

django-stubs/template/backends/django.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ from .base import BaseEngine, _EngineTemplate
1111
class DjangoTemplates(BaseEngine):
1212
engine: Engine
1313
def __init__(self, params: dict[str, Any]) -> None: ...
14+
def from_string(self, template_code: str) -> Template: ...
15+
def get_template(self, template_name: str) -> Template: ...
1416
def get_templatetag_libraries(self, custom_libraries: dict[str, str]) -> dict[str, str]: ...
1517

1618
def copy_exception(exc: TemplateDoesNotExist, backend: DjangoTemplates | None = None) -> TemplateDoesNotExist: ...

django-stubs/template/backends/dummy.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ from .base import BaseEngine
77

88
class TemplateStrings(BaseEngine):
99
def __init__(self, params: dict[str, dict[Any, Any] | list[Any] | bool | str]) -> None: ...
10+
def from_string(self, template_code: str) -> Template: ...
11+
def get_template(self, template_name: str) -> Template: ...
1012

1113
class Template(string.Template):
1214
template: str
13-
def render(self, context: dict[str, str] | None = ..., request: HttpRequest | None = ...) -> str: ...
15+
def render(self, context: dict[str, Any] | None = ..., request: HttpRequest | None = ...) -> str: ...

django-stubs/template/backends/jinja2.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ from collections.abc import Callable
22
from typing import Any
33

44
from _typeshed import Incomplete
5+
from django.http.request import HttpRequest
56
from django.template.exceptions import TemplateSyntaxError
67
from django.utils.functional import cached_property
78

@@ -11,6 +12,8 @@ class Jinja2(BaseEngine):
1112
env: Any
1213
context_processors: list[str]
1314
def __init__(self, params: dict[str, Any]) -> None: ...
15+
def from_string(self, template_code: str) -> Template: ...
16+
def get_template(self, template_name: str) -> Template: ...
1417
@cached_property
1518
def template_context_processors(self) -> list[Callable]: ...
1619

@@ -24,6 +27,6 @@ class Template:
2427
backend: Jinja2
2528
origin: Origin
2629
def __init__(self, template: Incomplete, backend: Jinja2) -> None: ...
27-
def render(self, context: Incomplete | None = ..., request: Incomplete | None = ...) -> Incomplete: ...
30+
def render(self, context: dict[str, Any] | None = ..., request: HttpRequest | None = ...) -> str: ...
2831

2932
def get_exception_info(exception: TemplateSyntaxError) -> dict[str, Any]: ...

django-stubs/template/context.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,4 @@ class RequestContext(Context):
8888
def bind_template(self, template: Template) -> Iterator[None]: ...
8989
def new(self, values: _ContextValues | None = None) -> RequestContext: ...
9090

91-
def make_context(context: Any, request: HttpRequest | None = None, **kwargs: Any) -> Context: ...
91+
def make_context(context: dict[str, Any] | None, request: HttpRequest | None = None, **kwargs: Any) -> Context: ...

0 commit comments

Comments
 (0)