-
-
Notifications
You must be signed in to change notification settings - Fork 452
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
Make from_string()
and get_template()
return backend-specific template
#2400
Make from_string()
and get_template()
return backend-specific template
#2400
Conversation
The implementation of `make_context()` explicitly rejects everything other than `dict` or `None` by raising `TypeError`.
[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`).
Only the Django Template Language backend outputs `SafeString`.
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.
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.
7cfc407
to
01d0f81
Compare
This code: class Template(string.Template, _EngineTemplate): triggers this mypy error on Python 3.8:
What would be the best solution?
For now, I'll revert the commit, to make sure that all the CI checks pass before further review. |
… protocol" This reverts commit 509e368. Inheriting from both `string.Template` and `typing.Protocol` causes mypy to report a metaclass conflict on Python 3.8.
@@ -23,6 +21,6 @@ class BaseEngine: | |||
class _EngineTemplate(Protocol): | |||
def render( | |||
self, | |||
context: Context | dict[str, Any] | None = ..., |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you remove this? Context
can be passed to render()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the commit comment of 2a070e0: not all implementations of this render()
method accept Context
and the spec states that dict
must be used.
The naming is a bit confusing, as there are multiple classes named Template
and multiple render()
methods with different interfaces. The implementer of _EngineTemplate
is django.template.backends.django.Template
and the render()
method of that class doesn't accept Context
, as it calls make_context()
which explicitly rejects anything other than None
and dict
.
The django.template.base.Template.render()
method does accept Context
and in fact requires it, but that is not an implementation of the _EngineTemplate
protocol, despite using the same class and method name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I got it! Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Each template backend will only return instances of its own specific template class. For example,
django.template.backends.jinja2.Jinja2
only returnsdjango.template.backends.jinja2.Template
instances.Each backend-specific template class has some unique features that a Django app or tool might be interested in.
I had to include a bunch of cleanups as well, because the original signatures of
_EngineTemplate.render()
anddjango.template.backends.dummy.Template.render()
were incompatible.