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