OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """ | 2 """ |
3 jinja2.loaders | 3 jinja2.loaders |
4 ~~~~~~~~~~~~~~ | 4 ~~~~~~~~~~~~~~ |
5 | 5 |
6 Jinja loader classes. | 6 Jinja loader classes. |
7 | 7 |
8 :copyright: (c) 2010 by the Jinja Team. | 8 :copyright: (c) 2010 by the Jinja Team. |
9 :license: BSD, see LICENSE for more details. | 9 :license: BSD, see LICENSE for more details. |
10 """ | 10 """ |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 return environment.template_class.from_code(environment, code, | 134 return environment.template_class.from_code(environment, code, |
135 globals, uptodate) | 135 globals, uptodate) |
136 | 136 |
137 | 137 |
138 class FileSystemLoader(BaseLoader): | 138 class FileSystemLoader(BaseLoader): |
139 """Loads templates from the file system. This loader can find templates | 139 """Loads templates from the file system. This loader can find templates |
140 in folders on the file system and is the preferred way to load them. | 140 in folders on the file system and is the preferred way to load them. |
141 | 141 |
142 The loader takes the path to the templates as string, or if multiple | 142 The loader takes the path to the templates as string, or if multiple |
143 locations are wanted a list of them which is then looked up in the | 143 locations are wanted a list of them which is then looked up in the |
144 given order: | 144 given order:: |
145 | 145 |
146 >>> loader = FileSystemLoader('/path/to/templates') | 146 >>> loader = FileSystemLoader('/path/to/templates') |
147 >>> loader = FileSystemLoader(['/path/to/templates', '/other/path']) | 147 >>> loader = FileSystemLoader(['/path/to/templates', '/other/path']) |
148 | 148 |
149 Per default the template encoding is ``'utf-8'`` which can be changed | 149 Per default the template encoding is ``'utf-8'`` which can be changed |
150 by setting the `encoding` parameter to something else. | 150 by setting the `encoding` parameter to something else. |
| 151 |
| 152 To follow symbolic links, set the *followlinks* parameter to ``True``:: |
| 153 |
| 154 >>> loader = FileSystemLoader('/path/to/templates', followlinks=True) |
| 155 |
| 156 .. versionchanged:: 2.8+ |
| 157 The *followlinks* parameter was added. |
151 """ | 158 """ |
152 | 159 |
153 def __init__(self, searchpath, encoding='utf-8'): | 160 def __init__(self, searchpath, encoding='utf-8', followlinks=False): |
154 if isinstance(searchpath, string_types): | 161 if isinstance(searchpath, string_types): |
155 searchpath = [searchpath] | 162 searchpath = [searchpath] |
156 self.searchpath = list(searchpath) | 163 self.searchpath = list(searchpath) |
157 self.encoding = encoding | 164 self.encoding = encoding |
| 165 self.followlinks = followlinks |
158 | 166 |
159 def get_source(self, environment, template): | 167 def get_source(self, environment, template): |
160 pieces = split_template_path(template) | 168 pieces = split_template_path(template) |
161 for searchpath in self.searchpath: | 169 for searchpath in self.searchpath: |
162 filename = path.join(searchpath, *pieces) | 170 filename = path.join(searchpath, *pieces) |
163 f = open_if_exists(filename) | 171 f = open_if_exists(filename) |
164 if f is None: | 172 if f is None: |
165 continue | 173 continue |
166 try: | 174 try: |
167 contents = f.read().decode(self.encoding) | 175 contents = f.read().decode(self.encoding) |
168 finally: | 176 finally: |
169 f.close() | 177 f.close() |
170 | 178 |
171 mtime = path.getmtime(filename) | 179 mtime = path.getmtime(filename) |
| 180 |
172 def uptodate(): | 181 def uptodate(): |
173 try: | 182 try: |
174 return path.getmtime(filename) == mtime | 183 return path.getmtime(filename) == mtime |
175 except OSError: | 184 except OSError: |
176 return False | 185 return False |
177 return contents, filename, uptodate | 186 return contents, filename, uptodate |
178 raise TemplateNotFound(template) | 187 raise TemplateNotFound(template) |
179 | 188 |
180 def list_templates(self): | 189 def list_templates(self): |
181 found = set() | 190 found = set() |
182 for searchpath in self.searchpath: | 191 for searchpath in self.searchpath: |
183 for dirpath, dirnames, filenames in os.walk(searchpath): | 192 walk_dir = os.walk(searchpath, followlinks=self.followlinks) |
| 193 for dirpath, dirnames, filenames in walk_dir: |
184 for filename in filenames: | 194 for filename in filenames: |
185 template = os.path.join(dirpath, filename) \ | 195 template = os.path.join(dirpath, filename) \ |
186 [len(searchpath):].strip(os.path.sep) \ | 196 [len(searchpath):].strip(os.path.sep) \ |
187 .replace(os.path.sep, '/') | 197 .replace(os.path.sep, '/') |
188 if template[:2] == './': | 198 if template[:2] == './': |
189 template = template[2:] | 199 template = template[2:] |
190 if template not in found: | 200 if template not in found: |
191 found.add(template) | 201 found.add(template) |
192 return sorted(found) | 202 return sorted(found) |
193 | 203 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 source = self.mapping[template] | 284 source = self.mapping[template] |
275 return source, None, lambda: source == self.mapping.get(template) | 285 return source, None, lambda: source == self.mapping.get(template) |
276 raise TemplateNotFound(template) | 286 raise TemplateNotFound(template) |
277 | 287 |
278 def list_templates(self): | 288 def list_templates(self): |
279 return sorted(self.mapping) | 289 return sorted(self.mapping) |
280 | 290 |
281 | 291 |
282 class FunctionLoader(BaseLoader): | 292 class FunctionLoader(BaseLoader): |
283 """A loader that is passed a function which does the loading. The | 293 """A loader that is passed a function which does the loading. The |
284 function becomes the name of the template passed and has to return either | 294 function receives the name of the template and has to return either |
285 an unicode string with the template source, a tuple in the form ``(source, | 295 an unicode string with the template source, a tuple in the form ``(source, |
286 filename, uptodatefunc)`` or `None` if the template does not exist. | 296 filename, uptodatefunc)`` or `None` if the template does not exist. |
287 | 297 |
288 >>> def load_template(name): | 298 >>> def load_template(name): |
289 ... if name == 'index.html': | 299 ... if name == 'index.html': |
290 ... return '...' | 300 ... return '...' |
291 ... | 301 ... |
292 >>> loader = FunctionLoader(load_template) | 302 >>> loader = FunctionLoader(load_template) |
293 | 303 |
294 The `uptodatefunc` is a function that is called if autoreload is enabled | 304 The `uptodatefunc` is a function that is called if autoreload is enabled |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 return loader.get_source(environment, name) | 352 return loader.get_source(environment, name) |
343 except TemplateNotFound: | 353 except TemplateNotFound: |
344 # re-raise the exception with the correct fileame here. | 354 # re-raise the exception with the correct fileame here. |
345 # (the one that includes the prefix) | 355 # (the one that includes the prefix) |
346 raise TemplateNotFound(template) | 356 raise TemplateNotFound(template) |
347 | 357 |
348 @internalcode | 358 @internalcode |
349 def load(self, environment, name, globals=None): | 359 def load(self, environment, name, globals=None): |
350 loader, local_name = self.get_loader(name) | 360 loader, local_name = self.get_loader(name) |
351 try: | 361 try: |
352 return loader.load(environment, local_name) | 362 return loader.load(environment, local_name, globals) |
353 except TemplateNotFound: | 363 except TemplateNotFound: |
354 # re-raise the exception with the correct fileame here. | 364 # re-raise the exception with the correct fileame here. |
355 # (the one that includes the prefix) | 365 # (the one that includes the prefix) |
356 raise TemplateNotFound(name) | 366 raise TemplateNotFound(name) |
357 | 367 |
358 def list_templates(self): | 368 def list_templates(self): |
359 result = [] | 369 result = [] |
360 for prefix, loader in iteritems(self.mapping): | 370 for prefix, loader in iteritems(self.mapping): |
361 for template in loader.list_templates(): | 371 for template in loader.list_templates(): |
362 result.append(prefix + self.delimiter + template) | 372 result.append(prefix + self.delimiter + template) |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 mod = __import__(module, None, None, ['root']) | 472 mod = __import__(module, None, None, ['root']) |
463 except ImportError: | 473 except ImportError: |
464 raise TemplateNotFound(name) | 474 raise TemplateNotFound(name) |
465 | 475 |
466 # remove the entry from sys.modules, we only want the attribute | 476 # remove the entry from sys.modules, we only want the attribute |
467 # on the module object we have stored on the loader. | 477 # on the module object we have stored on the loader. |
468 sys.modules.pop(module, None) | 478 sys.modules.pop(module, None) |
469 | 479 |
470 return environment.template_class.from_module_dict( | 480 return environment.template_class.from_module_dict( |
471 environment, mod.__dict__, globals) | 481 environment, mod.__dict__, globals) |
OLD | NEW |