1
# Wrapper for loading templates from storage of some sort (e.g. filesystem, database).
3
# This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
4
# Each loader is expected to have this interface:
6
# callable(name, dirs=[])
8
# name is the template name.
9
# dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
11
# The loader should return a tuple of (template_source, path). The path returned
12
# might be shown to the user for debugging purposes, so it should identify where
13
# the template was loaded from.
15
# A loader may return an already-compiled template instead of the actual
16
# template source. In that case the path returned should be None, since the
17
# path information is associated with the template during the compilation,
18
# which has already been done.
20
# Each loader should have an "is_usable" attribute set. This is a boolean that
21
# specifies whether the loader can be used in this Python installation. Each
22
# loader is responsible for setting this when it's initialized.
24
# For example, the eggs loader (which is capable of loading templates from
25
# Python eggs) sets is_usable to False if the "pkg_resources" module isn't
26
# installed, because pkg_resources is necessary to read eggs.
28
from google.appengine._internal.django.core.exceptions import ImproperlyConfigured
29
from google.appengine._internal.django.template import Origin, Template, Context, TemplateDoesNotExist, add_to_builtins
30
from google.appengine._internal.django.utils.importlib import import_module
31
from google.appengine._internal.django.conf import settings
33
template_source_loaders = None
35
class BaseLoader(object):
38
def __init__(self, *args, **kwargs):
41
def __call__(self, template_name, template_dirs=None):
42
return self.load_template(template_name, template_dirs)
44
def load_template(self, template_name, template_dirs=None):
45
source, display_name = self.load_template_source(template_name, template_dirs)
46
origin = make_origin(display_name, self.load_template_source, template_name, template_dirs)
48
template = get_template_from_string(source, origin, template_name)
50
except TemplateDoesNotExist:
51
# If compiling the template we found raises TemplateDoesNotExist, back off to
52
# returning the source and display name for the template we were asked to load.
53
# This allows for correct identification (later) of the actual template that does
55
return source, display_name
57
def load_template_source(self, template_name, template_dirs=None):
59
Returns a tuple containing the source and origin for the given template
63
raise NotImplementedError
67
Resets any state maintained by the loader instance (e.g., cached
68
templates or cached loader modules).
73
class LoaderOrigin(Origin):
74
def __init__(self, display_name, loader, name, dirs):
75
super(LoaderOrigin, self).__init__(display_name)
76
self.loader, self.loadname, self.dirs = loader, name, dirs
79
return self.loader(self.loadname, self.dirs)[0]
81
def make_origin(display_name, loader, name, dirs):
82
if settings.TEMPLATE_DEBUG and display_name:
83
return LoaderOrigin(display_name, loader, name, dirs)
87
def find_template_loader(loader):
88
if isinstance(loader, (tuple, list)):
89
loader, args = loader[0], loader[1:]
92
if isinstance(loader, basestring):
93
module, attr = loader.rsplit('.', 1)
95
mod = import_module(module)
96
except ImportError, e:
97
raise ImproperlyConfigured('Error importing template source loader %s: "%s"' % (loader, e))
99
TemplateLoader = getattr(mod, attr)
100
except AttributeError, e:
101
raise ImproperlyConfigured('Error importing template source loader %s: "%s"' % (loader, e))
103
if hasattr(TemplateLoader, 'load_template_source'):
104
func = TemplateLoader(*args)
106
# Try loading module the old way - string is full path to callable
108
raise ImproperlyConfigured("Error importing template source loader %s - can't pass arguments to function-based loader." % loader)
109
func = TemplateLoader
111
if not func.is_usable:
113
warnings.warn("Your TEMPLATE_LOADERS setting includes %r, but your Python installation doesn't support that type of template loading. Consider removing that line from TEMPLATE_LOADERS." % loader)
118
raise ImproperlyConfigured('Loader does not define a "load_template" callable template source loader')
120
def find_template(name, dirs=None):
121
# Calculate template_source_loaders the first time the function is executed
122
# because putting this logic in the module-level namespace may cause
123
# circular import errors. See Django ticket #1292.
124
global template_source_loaders
125
if template_source_loaders is None:
127
for loader_name in settings.TEMPLATE_LOADERS:
128
loader = find_template_loader(loader_name)
129
if loader is not None:
130
loaders.append(loader)
131
template_source_loaders = tuple(loaders)
132
for loader in template_source_loaders:
134
source, display_name = loader(name, dirs)
135
return (source, make_origin(display_name, loader, name, dirs))
136
except TemplateDoesNotExist:
138
raise TemplateDoesNotExist(name)
140
def find_template_source(name, dirs=None):
141
# For backward compatibility
144
"`django.template.loaders.find_template_source` is deprecated; use `django.template.loaders.find_template` instead.",
145
PendingDeprecationWarning
147
template, origin = find_template(name, dirs)
148
if hasattr(template, 'render'):
149
raise Exception("Found a compiled template that is incompatible with the deprecated `django.template.loaders.find_template_source` function.")
150
return template, origin
152
def get_template(template_name):
154
Returns a compiled Template object for the given template name,
155
handling template inheritance recursively.
157
template, origin = find_template(template_name)
158
if not hasattr(template, 'render'):
159
# template needs to be compiled
160
template = get_template_from_string(template, origin, template_name)
163
def get_template_from_string(source, origin=None, name=None):
165
Returns a compiled Template object for the given template code,
166
handling template inheritance recursively.
168
return Template(source, origin, name)
170
def render_to_string(template_name, dictionary=None, context_instance=None):
172
Loads the given template_name and renders it with the given dictionary as
173
context. The template_name may be a string to load a single template using
174
get_template, or it may be a tuple to use select_template to find one of
175
the templates in the list. Returns a string.
177
dictionary = dictionary or {}
178
if isinstance(template_name, (list, tuple)):
179
t = select_template(template_name)
181
t = get_template(template_name)
183
context_instance.update(dictionary)
185
context_instance = Context(dictionary)
186
return t.render(context_instance)
188
def select_template(template_name_list):
189
"Given a list of template names, returns the first that can be loaded."
190
for template_name in template_name_list:
192
return get_template(template_name)
193
except TemplateDoesNotExist:
195
# If we get here, none of the templates could be loaded
196
raise TemplateDoesNotExist(', '.join(template_name_list))
198
add_to_builtins('google.appengine._internal.django.template.loader_tags')