1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# -*- coding: utf-8 -*- 2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez""" 3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez jinja2.loaders 4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ~~~~~~~~~~~~~~ 5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Jinja loader classes. 7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez :copyright: (c) 2010 by the Jinja Team. 9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez :license: BSD, see LICENSE for more details. 10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez""" 11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport os 12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport sys 13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport weakref 14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom types import ModuleType 15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom os import path 16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom hashlib import sha1 17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.exceptions import TemplateNotFound 18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.utils import open_if_exists, internalcode 19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2._compat import string_types, iteritems 20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef split_template_path(template): 23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Split a path into segments and perform a sanity check. If it detects 24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez '..' in the path it will raise a `TemplateNotFound` error. 25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pieces = [] 27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for piece in template.split('/'): 28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if path.sep in piece \ 29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez or (path.altsep and path.altsep in piece) or \ 30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez piece == path.pardir: 31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif piece and piece != '.': 33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pieces.append(piece) 34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return pieces 35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass BaseLoader(object): 38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Baseclass for all loaders. Subclass this and override `get_source` to 39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez implement a custom loading mechanism. The environment provides a 40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez `get_template` method that calls the loader's `load` method to get the 41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez :class:`Template` object. 42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez A very basic example for a loader that looks up templates on the file 44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez system could look like this:: 45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez from jinja2 import BaseLoader, TemplateNotFound 47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez from os.path import join, exists, getmtime 48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez class MyLoader(BaseLoader): 50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, path): 52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.path = path 53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez path = join(self.path, template) 56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not exists(path): 57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mtime = getmtime(path) 59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez with file(path) as f: 60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez source = f.read().decode('utf-8') 61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return source, path, lambda: mtime == getmtime(path) 62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez #: if set to `False` it indicates that the loader cannot provide access 65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez #: to the source of templates. 66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez #: 67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez #: .. versionadded:: 2.4 68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez has_source_access = True 69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Get the template source, filename and reload helper for a template. 72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez It's passed the environment and template name and has to return a 73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez tuple in the form ``(source, filename, uptodate)`` or raise a 74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez `TemplateNotFound` error if it can't locate the template. 75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez The source part of the returned tuple must be the source of the 77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez template as unicode string or a ASCII bytestring. The filename should 78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez be the name of the file on the filesystem if it was loaded from there, 79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez otherwise `None`. The filename is used by python for the tracebacks 80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if no loader extension is used. 81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez The last item in the tuple is the `uptodate` function. If auto 83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez reloading is enabled it's always called to check if the template 84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez changed. No arguments are passed so the function must store the 85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez old state somewhere (for example in a closure). If it returns `False` 86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez the template will be reloaded. 87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not self.has_source_access: 89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise RuntimeError('%s cannot provide access to the source' % 90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.__class__.__name__) 91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def list_templates(self): 94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Iterates over all templates. If the loader does not support that 95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez it should raise a :exc:`TypeError` which is the default behavior. 96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TypeError('this loader cannot iterate over all templates') 98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez @internalcode 100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def load(self, environment, name, globals=None): 101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Loads a template. This method looks up the template in the cache 102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez or loads one by calling :meth:`get_source`. Subclasses should not 103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez override this method as loaders working on collections of other 104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`) 105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez will not call this method but `get_source` directly. 106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez code = None 108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if globals is None: 109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez globals = {} 110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # first we try to get the source for this template together 112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # with the filename and the uptodate function. 113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez source, filename, uptodate = self.get_source(environment, name) 114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # try to load the code from the bytecode cache if there is a 116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # bytecode cache configured. 117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez bcc = environment.bytecode_cache 118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if bcc is not None: 119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez bucket = bcc.get_bucket(environment, name, filename, source) 120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez code = bucket.code 121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # if we don't have code so far (not cached, no longer up to 123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # date) etc. we compile the template 124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if code is None: 125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez code = environment.compile(source, name, filename) 126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # if the bytecode cache is available and the bucket doesn't 128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # have a code so far, we give the bucket the new code and put 129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # it back to the bytecode cache. 130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if bcc is not None and bucket.code is None: 131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez bucket.code = code 132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez bcc.set_bucket(bucket) 133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return environment.template_class.from_code(environment, code, 135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez globals, uptodate) 136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass FileSystemLoader(BaseLoader): 139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Loads templates from the file system. This loader can find templates 140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez in folders on the file system and is the preferred way to load them. 141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez The loader takes the path to the templates as string, or if multiple 143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez locations are wanted a list of them which is then looked up in the 144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez given order: 145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> loader = FileSystemLoader('/path/to/templates') 147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> loader = FileSystemLoader(['/path/to/templates', '/other/path']) 148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Per default the template encoding is ``'utf-8'`` which can be changed 150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez by setting the `encoding` parameter to something else. 151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, searchpath, encoding='utf-8'): 154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if isinstance(searchpath, string_types): 155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez searchpath = [searchpath] 156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.searchpath = list(searchpath) 157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.encoding = encoding 158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pieces = split_template_path(template) 161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for searchpath in self.searchpath: 162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez filename = path.join(searchpath, *pieces) 163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez f = open_if_exists(filename) 164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if f is None: 165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez continue 166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez contents = f.read().decode(self.encoding) 168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez finally: 169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez f.close() 170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mtime = path.getmtime(filename) 172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def uptodate(): 173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return path.getmtime(filename) == mtime 175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except OSError: 176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return False 177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return contents, filename, uptodate 178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def list_templates(self): 181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez found = set() 182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for searchpath in self.searchpath: 183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for dirpath, dirnames, filenames in os.walk(searchpath): 184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for filename in filenames: 185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez template = os.path.join(dirpath, filename) \ 186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez [len(searchpath):].strip(os.path.sep) \ 187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez .replace(os.path.sep, '/') 188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if template[:2] == './': 189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez template = template[2:] 190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if template not in found: 191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez found.add(template) 192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return sorted(found) 193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass PackageLoader(BaseLoader): 196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Load templates from python eggs or packages. It is constructed with 197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez the name of the python package and the path to the templates in that 198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez package:: 199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez loader = PackageLoader('mypackage', 'views') 201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez If the package path is not given, ``'templates'`` is assumed. 203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Per default the template encoding is ``'utf-8'`` which can be changed 205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez by setting the `encoding` parameter to something else. Due to the nature 206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez of eggs it's only possible to reload templates if the package was loaded 207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez from the file system and not a zip file. 208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, package_name, package_path='templates', 211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez encoding='utf-8'): 212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez from pkg_resources import DefaultProvider, ResourceManager, \ 213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez get_provider 214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez provider = get_provider(package_name) 215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.encoding = encoding 216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.manager = ResourceManager() 217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.filesystem_bound = isinstance(provider, DefaultProvider) 218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.provider = provider 219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.package_path = package_path 220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pieces = split_template_path(template) 223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez p = '/'.join((self.package_path,) + tuple(pieces)) 224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not self.provider.has_resource(p): 225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez filename = uptodate = None 228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.filesystem_bound: 229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez filename = self.provider.get_resource_filename(self.manager, p) 230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mtime = path.getmtime(filename) 231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def uptodate(): 232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return path.getmtime(filename) == mtime 234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except OSError: 235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return False 236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez source = self.provider.get_resource_string(self.manager, p) 238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return source.decode(self.encoding), filename, uptodate 239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def list_templates(self): 241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez path = self.package_path 242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if path[:2] == './': 243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez path = path[2:] 244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif path == '.': 245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez path = '' 246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez offset = len(path) 247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez results = [] 248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def _walk(path): 249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for filename in self.provider.resource_listdir(path): 250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez fullname = path + '/' + filename 251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.provider.resource_isdir(fullname): 252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez _walk(fullname) 253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez results.append(fullname[offset:].lstrip('/')) 255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez _walk(path) 256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez results.sort() 257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return results 258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass DictLoader(BaseLoader): 261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Loads a template from a python dict. It's passed a dict of unicode 262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez strings bound to template names. This loader is useful for unittesting: 263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> loader = DictLoader({'index.html': 'source here'}) 265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Because auto reloading is rarely useful this is disabled per default. 267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, mapping): 270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.mapping = mapping 271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if template in self.mapping: 274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez source = self.mapping[template] 275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return source, None, lambda: source == self.mapping.get(template) 276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def list_templates(self): 279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return sorted(self.mapping) 280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass FunctionLoader(BaseLoader): 283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """A loader that is passed a function which does the loading. The 284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez function becomes the name of the template passed and has to return either 285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez an unicode string with the template source, a tuple in the form ``(source, 286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez filename, uptodatefunc)`` or `None` if the template does not exist. 287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> def load_template(name): 289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... if name == 'index.html': 290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... return '...' 291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... 292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> loader = FunctionLoader(load_template) 293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez The `uptodatefunc` is a function that is called if autoreload is enabled 295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez and has to return `True` if the template is still up to date. For more 296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez details have a look at :meth:`BaseLoader.get_source` which has the same 297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return value. 298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, load_func): 301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.load_func = load_func 302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez rv = self.load_func(template) 305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if rv is None: 306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif isinstance(rv, string_types): 308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return rv, None, None 309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return rv 310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass PrefixLoader(BaseLoader): 313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """A loader that is passed a dict of loaders where each loader is bound 314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez to a prefix. The prefix is delimited from the template by a slash per 315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez default, which can be changed by setting the `delimiter` argument to 316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez something else:: 317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez loader = PrefixLoader({ 319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'app1': PackageLoader('mypackage.app1'), 320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'app2': PackageLoader('mypackage.app2') 321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez }) 322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez By loading ``'app1/index.html'`` the file from the app1 package is loaded, 324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez by loading ``'app2/index.html'`` the file from the second. 325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 327645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, mapping, delimiter='/'): 328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.mapping = mapping 329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.delimiter = delimiter 330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_loader(self, template): 332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez prefix, name = template.split(self.delimiter, 1) 334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez loader = self.mapping[prefix] 335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except (ValueError, KeyError): 336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return loader, name 338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez loader, name = self.get_loader(template) 341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return loader.get_source(environment, name) 343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except TemplateNotFound: 344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # re-raise the exception with the correct fileame here. 345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # (the one that includes the prefix) 346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez @internalcode 349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def load(self, environment, name, globals=None): 350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez loader, local_name = self.get_loader(name) 351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return loader.load(environment, local_name) 353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except TemplateNotFound: 354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # re-raise the exception with the correct fileame here. 355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # (the one that includes the prefix) 356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(name) 357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def list_templates(self): 359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez result = [] 360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for prefix, loader in iteritems(self.mapping): 361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for template in loader.list_templates(): 362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez result.append(prefix + self.delimiter + template) 363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return result 364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 365645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 366645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass ChoiceLoader(BaseLoader): 367645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """This loader works like the `PrefixLoader` just that no prefix is 368645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez specified. If a template could not be found by one loader the next one 369645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez is tried. 370645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 371645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> loader = ChoiceLoader([ 372645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... FileSystemLoader('/path/to/user/templates'), 373645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... FileSystemLoader('/path/to/system/templates') 374645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... ]) 375645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 376645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez This is useful if you want to allow users to override builtin templates 377645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez from a different location. 378645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 379645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 380645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, loaders): 381645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.loaders = loaders 382645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 383645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_source(self, environment, template): 384645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for loader in self.loaders: 385645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 386645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return loader.get_source(environment, template) 387645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except TemplateNotFound: 388645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pass 389645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(template) 390645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 391645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez @internalcode 392645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def load(self, environment, name, globals=None): 393645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for loader in self.loaders: 394645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 395645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return loader.load(environment, name, globals) 396645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except TemplateNotFound: 397645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pass 398645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(name) 399645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 400645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def list_templates(self): 401645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez found = set() 402645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for loader in self.loaders: 403645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez found.update(loader.list_templates()) 404645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return sorted(found) 405645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 406645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 407645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass _TemplateModule(ModuleType): 408645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Like a normal module but with support for weak references""" 409645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 410645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 411645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass ModuleLoader(BaseLoader): 412645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """This loader loads templates from precompiled templates. 413645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 414645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Example usage: 415645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 416645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez >>> loader = ChoiceLoader([ 417645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... ModuleLoader('/path/to/compiled/templates'), 418645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... FileSystemLoader('/path/to/templates') 419645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ... ]) 420645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 421645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Templates can be precompiled with :meth:`Environment.compile_templates`. 422645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 423645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 424645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez has_source_access = False 425645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 426645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, path): 427645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez package_name = '_jinja2_module_templates_%x' % id(self) 428645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 429645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # create a fake module that looks for the templates in the 430645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # path given. 431645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mod = _TemplateModule(package_name) 432645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if isinstance(path, string_types): 433645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez path = [path] 434645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 435645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez path = list(path) 436645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mod.__path__ = path 437645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 438645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez sys.modules[package_name] = weakref.proxy(mod, 439645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lambda x: sys.modules.pop(package_name, None)) 440645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 441645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # the only strong reference, the sys.modules entry is weak 442645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # so that the garbage collector can remove it once the 443645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # loader that created it goes out of business. 444645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.module = mod 445645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.package_name = package_name 446645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 447645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez @staticmethod 448645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_template_key(name): 449645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest() 450645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 451645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez @staticmethod 452645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def get_module_filename(name): 453645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return ModuleLoader.get_template_key(name) + '.py' 454645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 455645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez @internalcode 456645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def load(self, environment, name, globals=None): 457645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez key = self.get_template_key(name) 458645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez module = '%s.%s' % (self.package_name, key) 459645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mod = getattr(self.module, module, None) 460645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if mod is None: 461645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 462645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez mod = __import__(module, None, None, ['root']) 463645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez except ImportError: 464645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise TemplateNotFound(name) 465645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 466645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # remove the entry from sys.modules, we only want the attribute 467645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # on the module object we have stored on the loader. 468645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez sys.modules.pop(module, None) 469645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 470645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return environment.template_class.from_module_dict( 471645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez environment, mod.__dict__, globals) 472