Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/template/engine.py: 39%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

114 statements  

1import functools 

2 

3from django.core.exceptions import ImproperlyConfigured 

4from django.utils.functional import cached_property 

5from django.utils.module_loading import import_string 

6 

7from .base import Template 

8from .context import Context, _builtin_context_processors 

9from .exceptions import TemplateDoesNotExist 

10from .library import import_library 

11 

12 

13class Engine: 

14 default_builtins = [ 

15 "django.template.defaulttags", 

16 "django.template.defaultfilters", 

17 "django.template.loader_tags", 

18 ] 

19 

20 def __init__( 

21 self, 

22 dirs=None, 

23 app_dirs=False, 

24 context_processors=None, 

25 debug=False, 

26 loaders=None, 

27 string_if_invalid="", 

28 file_charset="utf-8", 

29 libraries=None, 

30 builtins=None, 

31 autoescape=True, 

32 ): 

33 if dirs is None: 

34 dirs = [] 

35 if context_processors is None: 

36 context_processors = [] 

37 if loaders is None: 

38 loaders = ["django.template.loaders.filesystem.Loader"] 

39 if app_dirs: 

40 loaders += ["django.template.loaders.app_directories.Loader"] 

41 loaders = [("django.template.loaders.cached.Loader", loaders)] 

42 else: 

43 if app_dirs: 

44 raise ImproperlyConfigured( 

45 "app_dirs must not be set when loaders is defined." 

46 ) 

47 if libraries is None: 

48 libraries = {} 

49 if builtins is None: 

50 builtins = [] 

51 

52 self.dirs = dirs 

53 self.app_dirs = app_dirs 

54 self.autoescape = autoescape 

55 self.context_processors = context_processors 

56 self.debug = debug 

57 self.loaders = loaders 

58 self.string_if_invalid = string_if_invalid 

59 self.file_charset = file_charset 

60 self.libraries = libraries 

61 self.template_libraries = self.get_template_libraries(libraries) 

62 self.builtins = self.default_builtins + builtins 

63 self.template_builtins = self.get_template_builtins(self.builtins) 

64 

65 def __repr__(self): 

66 return ( 

67 "<%s:%s app_dirs=%s%s debug=%s loaders=%s string_if_invalid=%s " 

68 "file_charset=%s%s%s autoescape=%s>" 

69 ) % ( 

70 self.__class__.__qualname__, 

71 "" if not self.dirs else " dirs=%s" % repr(self.dirs), 

72 self.app_dirs, 

73 ( 

74 "" 

75 if not self.context_processors 

76 else " context_processors=%s" % repr(self.context_processors) 

77 ), 

78 self.debug, 

79 repr(self.loaders), 

80 repr(self.string_if_invalid), 

81 repr(self.file_charset), 

82 "" if not self.libraries else " libraries=%s" % repr(self.libraries), 

83 "" if not self.builtins else " builtins=%s" % repr(self.builtins), 

84 repr(self.autoescape), 

85 ) 

86 

87 @staticmethod 

88 @functools.lru_cache 

89 def get_default(): 

90 """ 

91 Return the first DjangoTemplates backend that's configured, or raise 

92 ImproperlyConfigured if none are configured. 

93 

94 This is required for preserving historical APIs that rely on a 

95 globally available, implicitly configured engine such as: 

96 

97 >>> from django.template import Context, Template 

98 >>> template = Template("Hello {{ name }}!") 

99 >>> context = Context({'name': "world"}) 

100 >>> template.render(context) 

101 'Hello world!' 

102 """ 

103 # Since Engine is imported in django.template and since 

104 # DjangoTemplates is a wrapper around this Engine class, 

105 # local imports are required to avoid import loops. 

106 from django.template import engines 

107 from django.template.backends.django import DjangoTemplates 

108 

109 for engine in engines.all(): 

110 if isinstance(engine, DjangoTemplates): 

111 return engine.engine 

112 raise ImproperlyConfigured("No DjangoTemplates backend is configured.") 

113 

114 @cached_property 

115 def template_context_processors(self): 

116 context_processors = _builtin_context_processors 

117 context_processors += tuple(self.context_processors) 

118 return tuple(import_string(path) for path in context_processors) 

119 

120 def get_template_builtins(self, builtins): 

121 return [import_library(x) for x in builtins] 

122 

123 def get_template_libraries(self, libraries): 

124 loaded = {} 

125 for name, path in libraries.items(): 

126 loaded[name] = import_library(path) 

127 return loaded 

128 

129 @cached_property 

130 def template_loaders(self): 

131 return self.get_template_loaders(self.loaders) 

132 

133 def get_template_loaders(self, template_loaders): 

134 loaders = [] 

135 for template_loader in template_loaders: 

136 loader = self.find_template_loader(template_loader) 

137 if loader is not None: 

138 loaders.append(loader) 

139 return loaders 

140 

141 def find_template_loader(self, loader): 

142 if isinstance(loader, (tuple, list)): 

143 loader, *args = loader 

144 else: 

145 args = [] 

146 

147 if isinstance(loader, str): 

148 loader_class = import_string(loader) 

149 return loader_class(self, *args) 

150 else: 

151 raise ImproperlyConfigured( 

152 "Invalid value in template loaders configuration: %r" % loader 

153 ) 

154 

155 def find_template(self, name, dirs=None, skip=None): 

156 tried = [] 

157 for loader in self.template_loaders: 

158 try: 

159 template = loader.get_template(name, skip=skip) 

160 return template, template.origin 

161 except TemplateDoesNotExist as e: 

162 tried.extend(e.tried) 

163 raise TemplateDoesNotExist(name, tried=tried) 

164 

165 def from_string(self, template_code): 

166 """ 

167 Return a compiled Template object for the given template code, 

168 handling template inheritance recursively. 

169 """ 

170 return Template(template_code, engine=self) 

171 

172 def get_template(self, template_name): 

173 """ 

174 Return a compiled Template object for the given template name, 

175 handling template inheritance recursively. 

176 """ 

177 template, origin = self.find_template(template_name) 

178 if not hasattr(template, "render"): 

179 # template needs to be compiled 

180 template = Template(template, origin, template_name, engine=self) 

181 return template 

182 

183 def render_to_string(self, template_name, context=None): 

184 """ 

185 Render the template specified by template_name with the given context. 

186 For use in Django's test suite. 

187 """ 

188 if isinstance(template_name, (list, tuple)): 

189 t = self.select_template(template_name) 

190 else: 

191 t = self.get_template(template_name) 

192 # Django < 1.8 accepted a Context in `context` even though that's 

193 # unintended. Preserve this ability but don't rewrap `context`. 

194 if isinstance(context, Context): 

195 return t.render(context) 

196 else: 

197 return t.render(Context(context, autoescape=self.autoescape)) 

198 

199 def select_template(self, template_name_list): 

200 """ 

201 Given a list of template names, return the first that can be loaded. 

202 """ 

203 if not template_name_list: 

204 raise TemplateDoesNotExist("No template names provided") 

205 not_found = [] 

206 for template_name in template_name_list: 

207 try: 

208 return self.get_template(template_name) 

209 except TemplateDoesNotExist as exc: 

210 if exc.args[0] not in not_found: 

211 not_found.append(exc.args[0]) 

212 continue 

213 # If we get here, none of the templates could be loaded 

214 raise TemplateDoesNotExist(", ".join(not_found))