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

114 statements  

« prev     ^ index     » next       coverage.py v7.0.5, created at 2023-01-17 06:13 +0000

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 if not self.context_processors 

75 else " context_processors=%s" % repr(self.context_processors), 

76 self.debug, 

77 repr(self.loaders), 

78 repr(self.string_if_invalid), 

79 repr(self.file_charset), 

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

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

82 repr(self.autoescape), 

83 ) 

84 

85 @staticmethod 

86 @functools.lru_cache 

87 def get_default(): 

88 """ 

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

90 ImproperlyConfigured if none are configured. 

91 

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

93 globally available, implicitly configured engine such as: 

94 

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

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

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

98 >>> template.render(context) 

99 'Hello world!' 

100 """ 

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

102 # DjangoTemplates is a wrapper around this Engine class, 

103 # local imports are required to avoid import loops. 

104 from django.template import engines 

105 from django.template.backends.django import DjangoTemplates 

106 

107 for engine in engines.all(): 

108 if isinstance(engine, DjangoTemplates): 

109 return engine.engine 

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

111 

112 @cached_property 

113 def template_context_processors(self): 

114 context_processors = _builtin_context_processors 

115 context_processors += tuple(self.context_processors) 

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

117 

118 def get_template_builtins(self, builtins): 

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

120 

121 def get_template_libraries(self, libraries): 

122 loaded = {} 

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

124 loaded[name] = import_library(path) 

125 return loaded 

126 

127 @cached_property 

128 def template_loaders(self): 

129 return self.get_template_loaders(self.loaders) 

130 

131 def get_template_loaders(self, template_loaders): 

132 loaders = [] 

133 for template_loader in template_loaders: 

134 loader = self.find_template_loader(template_loader) 

135 if loader is not None: 

136 loaders.append(loader) 

137 return loaders 

138 

139 def find_template_loader(self, loader): 

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

141 loader, *args = loader 

142 else: 

143 args = [] 

144 

145 if isinstance(loader, str): 

146 loader_class = import_string(loader) 

147 return loader_class(self, *args) 

148 else: 

149 raise ImproperlyConfigured( 

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

151 ) 

152 

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

154 tried = [] 

155 for loader in self.template_loaders: 

156 try: 

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

158 return template, template.origin 

159 except TemplateDoesNotExist as e: 

160 tried.extend(e.tried) 

161 raise TemplateDoesNotExist(name, tried=tried) 

162 

163 def from_string(self, template_code): 

164 """ 

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

166 handling template inheritance recursively. 

167 """ 

168 return Template(template_code, engine=self) 

169 

170 def get_template(self, template_name): 

171 """ 

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

173 handling template inheritance recursively. 

174 """ 

175 template, origin = self.find_template(template_name) 

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

177 # template needs to be compiled 

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

179 return template 

180 

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

182 """ 

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

184 For use in Django's test suite. 

185 """ 

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

187 t = self.select_template(template_name) 

188 else: 

189 t = self.get_template(template_name) 

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

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

192 if isinstance(context, Context): 

193 return t.render(context) 

194 else: 

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

196 

197 def select_template(self, template_name_list): 

198 """ 

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

200 """ 

201 if not template_name_list: 

202 raise TemplateDoesNotExist("No template names provided") 

203 not_found = [] 

204 for template_name in template_name_list: 

205 try: 

206 return self.get_template(template_name) 

207 except TemplateDoesNotExist as exc: 

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

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

210 continue 

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

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