Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask/templating.py: 24%
94 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
1import typing as t
3from jinja2 import BaseLoader
4from jinja2 import Environment as BaseEnvironment
5from jinja2 import Template
6from jinja2 import TemplateNotFound
8from .globals import _app_ctx_stack
9from .globals import _request_ctx_stack
10from .signals import before_render_template
11from .signals import template_rendered
13if t.TYPE_CHECKING:
14 from .app import Flask
15 from .scaffold import Scaffold
18def _default_template_ctx_processor() -> t.Dict[str, t.Any]:
19 """Default template context processor. Injects `request`,
20 `session` and `g`.
21 """
22 reqctx = _request_ctx_stack.top
23 appctx = _app_ctx_stack.top
24 rv = {}
25 if appctx is not None:
26 rv["g"] = appctx.g
27 if reqctx is not None:
28 rv["request"] = reqctx.request
29 rv["session"] = reqctx.session
30 return rv
33class Environment(BaseEnvironment):
34 """Works like a regular Jinja2 environment but has some additional
35 knowledge of how Flask's blueprint works so that it can prepend the
36 name of the blueprint to referenced templates if necessary.
37 """
39 def __init__(self, app: "Flask", **options: t.Any) -> None:
40 if "loader" not in options:
41 options["loader"] = app.create_global_jinja_loader()
42 BaseEnvironment.__init__(self, **options)
43 self.app = app
46class DispatchingJinjaLoader(BaseLoader):
47 """A loader that looks for templates in the application and all
48 the blueprint folders.
49 """
51 def __init__(self, app: "Flask") -> None:
52 self.app = app
54 def get_source( # type: ignore
55 self, environment: Environment, template: str
56 ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable]]:
57 if self.app.config["EXPLAIN_TEMPLATE_LOADING"]:
58 return self._get_source_explained(environment, template)
59 return self._get_source_fast(environment, template)
61 def _get_source_explained(
62 self, environment: Environment, template: str
63 ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable]]:
64 attempts = []
65 rv: t.Optional[t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]]
66 trv: t.Optional[
67 t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]
68 ] = None
70 for srcobj, loader in self._iter_loaders(template):
71 try:
72 rv = loader.get_source(environment, template)
73 if trv is None:
74 trv = rv
75 except TemplateNotFound:
76 rv = None
77 attempts.append((loader, srcobj, rv))
79 from .debughelpers import explain_template_loading_attempts
81 explain_template_loading_attempts(self.app, template, attempts)
83 if trv is not None:
84 return trv
85 raise TemplateNotFound(template)
87 def _get_source_fast(
88 self, environment: Environment, template: str
89 ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable]]:
90 for _srcobj, loader in self._iter_loaders(template):
91 try:
92 return loader.get_source(environment, template)
93 except TemplateNotFound:
94 continue
95 raise TemplateNotFound(template)
97 def _iter_loaders(
98 self, template: str
99 ) -> t.Generator[t.Tuple["Scaffold", BaseLoader], None, None]:
100 loader = self.app.jinja_loader
101 if loader is not None:
102 yield self.app, loader
104 for blueprint in self.app.iter_blueprints():
105 loader = blueprint.jinja_loader
106 if loader is not None:
107 yield blueprint, loader
109 def list_templates(self) -> t.List[str]:
110 result = set()
111 loader = self.app.jinja_loader
112 if loader is not None:
113 result.update(loader.list_templates())
115 for blueprint in self.app.iter_blueprints():
116 loader = blueprint.jinja_loader
117 if loader is not None:
118 for template in loader.list_templates():
119 result.add(template)
121 return list(result)
124def _render(template: Template, context: dict, app: "Flask") -> str:
125 """Renders the template and fires the signal"""
127 before_render_template.send(app, template=template, context=context)
128 rv = template.render(context)
129 template_rendered.send(app, template=template, context=context)
130 return rv
133def render_template(
134 template_name_or_list: t.Union[str, Template, t.List[t.Union[str, Template]]],
135 **context: t.Any
136) -> str:
137 """Renders a template from the template folder with the given
138 context.
140 :param template_name_or_list: the name of the template to be
141 rendered, or an iterable with template names
142 the first one existing will be rendered
143 :param context: the variables that should be available in the
144 context of the template.
145 """
146 ctx = _app_ctx_stack.top
148 if ctx is None:
149 raise RuntimeError(
150 "This function can only be used when an application context is active."
151 )
153 ctx.app.update_template_context(context)
154 return _render(
155 ctx.app.jinja_env.get_or_select_template(template_name_or_list),
156 context,
157 ctx.app,
158 )
161def render_template_string(source: str, **context: t.Any) -> str:
162 """Renders a template from the given template source string
163 with the given context. Template variables will be autoescaped.
165 :param source: the source code of the template to be
166 rendered
167 :param context: the variables that should be available in the
168 context of the template.
169 """
170 ctx = _app_ctx_stack.top
172 if ctx is None:
173 raise RuntimeError(
174 "This function can only be used when an application context is active."
175 )
177 ctx.app.update_template_context(context)
178 return _render(ctx.app.jinja_env.from_string(source), context, ctx.app)