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

1import typing as t 

2 

3from jinja2 import BaseLoader 

4from jinja2 import Environment as BaseEnvironment 

5from jinja2 import Template 

6from jinja2 import TemplateNotFound 

7 

8from .globals import _app_ctx_stack 

9from .globals import _request_ctx_stack 

10from .signals import before_render_template 

11from .signals import template_rendered 

12 

13if t.TYPE_CHECKING: 

14 from .app import Flask 

15 from .scaffold import Scaffold 

16 

17 

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 

31 

32 

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 """ 

38 

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 

44 

45 

46class DispatchingJinjaLoader(BaseLoader): 

47 """A loader that looks for templates in the application and all 

48 the blueprint folders. 

49 """ 

50 

51 def __init__(self, app: "Flask") -> None: 

52 self.app = app 

53 

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) 

60 

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 

69 

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)) 

78 

79 from .debughelpers import explain_template_loading_attempts 

80 

81 explain_template_loading_attempts(self.app, template, attempts) 

82 

83 if trv is not None: 

84 return trv 

85 raise TemplateNotFound(template) 

86 

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) 

96 

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 

103 

104 for blueprint in self.app.iter_blueprints(): 

105 loader = blueprint.jinja_loader 

106 if loader is not None: 

107 yield blueprint, loader 

108 

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()) 

114 

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) 

120 

121 return list(result) 

122 

123 

124def _render(template: Template, context: dict, app: "Flask") -> str: 

125 """Renders the template and fires the signal""" 

126 

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 

131 

132 

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. 

139 

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 

147 

148 if ctx is None: 

149 raise RuntimeError( 

150 "This function can only be used when an application context is active." 

151 ) 

152 

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 ) 

159 

160 

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. 

164 

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 

171 

172 if ctx is None: 

173 raise RuntimeError( 

174 "This function can only be used when an application context is active." 

175 ) 

176 

177 ctx.app.update_template_context(context) 

178 return _render(ctx.app.jinja_env.from_string(source), context, ctx.app)