Skip to content

Commit 856b045

Browse files
committed
Rename templates module, return Template type
1 parent b8c759f commit 856b045

File tree

22 files changed

+197
-178
lines changed

22 files changed

+197
-178
lines changed

bolt-auth/bolt/auth/forms.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unicodedata
22

3-
from bolt import forms, jinja
3+
from bolt import forms
4+
from bolt.templates import Template
45
from bolt.auth import authenticate, get_user_model, password_validation
56
from bolt.auth.models import User
67
from bolt.auth.tokens import default_token_generator
@@ -279,16 +280,16 @@ def send_mail(
279280
"""
280281
Send a bolt.mail.EmailMultiAlternatives to `to_email`.
281282
"""
282-
template = jinja.environment.from_string(subject_template_name)
283+
template = Template(subject_template_name)
283284
subject = template.render(context)
284285
# Email subject *must not* contain newlines
285286
subject = "".join(subject.splitlines())
286-
template = jinja.environment.from_string(email_template_name)
287+
template = Template(email_template_name)
287288
body = template.render(context)
288289

289290
email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
290291
if html_email_template_name is not None:
291-
template = jinja.environment.from_string(html_email_template_name)
292+
template = Template(html_email_template_name)
292293
html_email = template.render(context)
293294
email_message.attach_alternative(html_email, "text/html")
294295

bolt-htmx/bolt/htmx/jinja.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import jinja2
22
from jinja2.ext import Extension
33

4-
from bolt.jinja.extensions import InclusionTagExtension
4+
from bolt.templates.jinja.extensions import InclusionTagExtension
55

66

77
class HTMXJSExtension(InclusionTagExtension):

bolt-htmx/bolt/htmx/views.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,18 @@
66
class HTMXViewMixin:
77
htmx_template_name = ""
88

9-
def get_template_response(self, context=None) -> HttpResponse:
9+
def get_template(self):
1010
if self.is_htmx_request and self.htmx_fragment_name:
1111
from .jinja import HTMXFragmentExtension
1212

13-
template = self.get_template()
14-
if context is None:
15-
context = self.get_context()
16-
rendered = HTMXFragmentExtension.render_template_fragment(
13+
template = super().get_template()
14+
return HTMXFragmentExtension.render_template_fragment(
1715
template=template,
1816
fragment_name=self.htmx_fragment_name,
1917
context=context,
2018
)
21-
return HttpResponse(rendered, content_type=self.content_type)
2219

23-
return super().get_template_response(context=context)
20+
return super().get_template()
2421

2522
def get_response(self):
2623
if self.is_htmx_request:

bolt-importmap/bolt/importmap/jinja.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22

3-
from bolt.jinja.extensions import InclusionTagExtension
43
from bolt.runtime import settings
4+
from bolt.templates.jinja.extensions import InclusionTagExtension
55

66
from .core import Importmap
77

bolt-oauth/bolt/oauth/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from bolt import jinja
21
from bolt.auth.mixins import LoginRequiredMixin
32
from bolt.http import HttpResponseBadRequest, HttpResponseRedirect
3+
from bolt.templates import jinja
44
from bolt.views import View
55

66
from .exceptions import (

bolt-pages/bolt/pages/pages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import frontmatter
44
import pycmarkgfm
55

6-
from bolt.jinja import environment
76
from bolt.runtime import settings
7+
from bolt.templates.jinja import environment
88
from bolt.utils.functional import cached_property
99

1010

bolt-tailwind/bolt/tailwind/jinja.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from bolt.assets.finders import APP_ASSETS_DIR
2-
from bolt.jinja.extensions import InclusionTagExtension
32
from bolt.runtime import settings
3+
from bolt.templates.jinja.extensions import InclusionTagExtension
44

55

66
class TailwindCSSExtension(InclusionTagExtension):

bolt-toolbar/bolt/toolbar/jinja.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from bolt.jinja.extensions import InclusionTagExtension
21
from bolt.runtime import settings
2+
from bolt.templates.jinja.extensions import InclusionTagExtension
33
from bolt.utils.module_loading import import_string
44

55

bolt/http/response.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,3 +717,117 @@ def __init__(
717717
kwargs.setdefault("content_type", "application/json")
718718
data = json.dumps(data, cls=encoder, **json_dumps_params)
719719
super().__init__(content=data, **kwargs)
720+
721+
722+
class ContentNotRenderedError(Exception):
723+
pass
724+
725+
726+
class RenderableResponse(HttpResponse):
727+
non_picklable_attrs = HttpResponse.non_picklable_attrs | frozenset(
728+
["render_func", "context_data", "_post_render_callbacks", "_request"]
729+
)
730+
731+
def __init__(
732+
self,
733+
render_func,
734+
context=None,
735+
content_type=None,
736+
status=None,
737+
charset=None,
738+
headers=None,
739+
):
740+
self.render_func = render_func
741+
742+
# It would seem obvious to call these next two members 'template' and
743+
# 'context', but those names are reserved as part of the test Client
744+
# API. To avoid the name collision, we use different names.
745+
self.context_data = context
746+
747+
self._post_render_callbacks = []
748+
749+
# content argument doesn't make sense here because it will be replaced
750+
# with rendered template so we always pass empty string in order to
751+
# prevent errors and provide shorter signature.
752+
super().__init__("", content_type, status, charset=charset, headers=headers)
753+
754+
# _is_rendered tracks whether the template and context has been baked
755+
# into a final response.
756+
# Super __init__ doesn't know any better than to set self.content to
757+
# the empty string we just gave it, which wrongly sets _is_rendered
758+
# True, so we initialize it to False after the call to super __init__.
759+
self._is_rendered = False
760+
761+
def __getstate__(self):
762+
"""
763+
Raise an exception if trying to pickle an unrendered response. Pickle
764+
only rendered data, not the data used to construct the response.
765+
"""
766+
if not self._is_rendered:
767+
raise ContentNotRenderedError(
768+
"The response content must be rendered before it can be pickled."
769+
)
770+
return super().__getstate__()
771+
772+
@property
773+
def rendered_content(self):
774+
"""Return the freshly rendered content for the template and context
775+
described by the TemplateResponse.
776+
777+
This *does not* set the final content of the response. To set the
778+
response content, you must either call render(), or set the
779+
content explicitly using the value of this property.
780+
"""
781+
return self.render_func(self.context_data)
782+
783+
def add_post_render_callback(self, callback):
784+
"""Add a new post-rendering callback.
785+
786+
If the response has already been rendered,
787+
invoke the callback immediately.
788+
"""
789+
if self._is_rendered:
790+
callback(self)
791+
else:
792+
self._post_render_callbacks.append(callback)
793+
794+
def render(self):
795+
"""Render (thereby finalizing) the content of the response.
796+
797+
If the content has already been rendered, this is a no-op.
798+
799+
Return the baked response instance.
800+
"""
801+
retval = self
802+
if not self._is_rendered:
803+
self.content = self.rendered_content
804+
for post_callback in self._post_render_callbacks:
805+
newretval = post_callback(retval)
806+
if newretval is not None:
807+
retval = newretval
808+
return retval
809+
810+
@property
811+
def is_rendered(self):
812+
return self._is_rendered
813+
814+
def __iter__(self):
815+
if not self._is_rendered:
816+
raise ContentNotRenderedError(
817+
"The response content must be rendered before it can be iterated over."
818+
)
819+
return super().__iter__()
820+
821+
@property
822+
def content(self):
823+
if not self._is_rendered:
824+
raise ContentNotRenderedError(
825+
"The response content must be rendered before it can be accessed."
826+
)
827+
return super().content
828+
829+
@content.setter
830+
def content(self, value):
831+
"""Set the content for the response."""
832+
HttpResponse.content.fset(self, value)
833+
self._is_rendered = True

bolt/jinja/context.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)