diff -r b758351d191f -r cc9b7e14412b web/lib/django/template/loader.py --- a/web/lib/django/template/loader.py Wed May 19 17:43:59 2010 +0200 +++ b/web/lib/django/template/loader.py Tue May 25 02:43:45 2010 +0200 @@ -12,6 +12,11 @@ # might be shown to the user for debugging purposes, so it should identify where # the template was loaded from. # +# A loader may return an already-compiled template instead of the actual +# template source. In that case the path returned should be None, since the +# path information is associated with the template during the compilation, +# which has already been done. +# # Each loader should have an "is_usable" attribute set. This is a boolean that # specifies whether the loader can be used in this Python installation. Each # loader is responsible for setting this when it's initialized. @@ -27,6 +32,44 @@ template_source_loaders = None +class BaseLoader(object): + is_usable = False + + def __init__(self, *args, **kwargs): + pass + + def __call__(self, template_name, template_dirs=None): + return self.load_template(template_name, template_dirs) + + def load_template(self, template_name, template_dirs=None): + source, display_name = self.load_template_source(template_name, template_dirs) + origin = make_origin(display_name, self.load_template_source, template_name, template_dirs) + try: + template = get_template_from_string(source, origin, template_name) + return template, None + except TemplateDoesNotExist: + # If compiling the template we found raises TemplateDoesNotExist, back off to + # returning the source and display name for the template we were asked to load. + # This allows for correct identification (later) of the actual template that does + # not exist. + return source, display_name + + def load_template_source(self, template_name, template_dirs=None): + """ + Returns a tuple containing the source and origin for the given template + name. + + """ + raise NotImplementedError + + def reset(self): + """ + Resets any state maintained by the loader instance (e.g., cached + templates or cached loader modules). + + """ + pass + class LoaderOrigin(Origin): def __init__(self, display_name, loader, name, dirs): super(LoaderOrigin, self).__init__(display_name) @@ -36,34 +79,55 @@ return self.loader(self.loadname, self.dirs)[0] def make_origin(display_name, loader, name, dirs): - if settings.TEMPLATE_DEBUG: + if settings.TEMPLATE_DEBUG and display_name: return LoaderOrigin(display_name, loader, name, dirs) else: return None -def find_template_source(name, dirs=None): +def find_template_loader(loader): + if isinstance(loader, (tuple, list)): + loader, args = loader[0], loader[1:] + else: + args = [] + if isinstance(loader, basestring): + module, attr = loader.rsplit('.', 1) + try: + mod = import_module(module) + except ImportError, e: + raise ImproperlyConfigured('Error importing template source loader %s: "%s"' % (loader, e)) + try: + TemplateLoader = getattr(mod, attr) + except AttributeError, e: + raise ImproperlyConfigured('Error importing template source loader %s: "%s"' % (loader, e)) + + if hasattr(TemplateLoader, 'load_template_source'): + func = TemplateLoader(*args) + else: + # Try loading module the old way - string is full path to callable + if args: + raise ImproperlyConfigured("Error importing template source loader %s - can't pass arguments to function-based loader." % loader) + func = TemplateLoader + + if not func.is_usable: + import warnings + 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) + return None + else: + return func + else: + raise ImproperlyConfigured('Loader does not define a "load_template" callable template source loader') + +def find_template(name, dirs=None): # Calculate template_source_loaders the first time the function is executed # because putting this logic in the module-level namespace may cause # circular import errors. See Django ticket #1292. global template_source_loaders if template_source_loaders is None: loaders = [] - for path in settings.TEMPLATE_LOADERS: - i = path.rfind('.') - module, attr = path[:i], path[i+1:] - try: - mod = import_module(module) - except ImportError, e: - raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e) - try: - func = getattr(mod, attr) - except AttributeError: - raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable template source loader' % (module, attr) - if not func.is_usable: - import warnings - 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." % path) - else: - loaders.append(func) + for loader_name in settings.TEMPLATE_LOADERS: + loader = find_template_loader(loader_name) + if loader is not None: + loaders.append(loader) template_source_loaders = tuple(loaders) for loader in template_source_loaders: try: @@ -71,15 +135,29 @@ return (source, make_origin(display_name, loader, name, dirs)) except TemplateDoesNotExist: pass - raise TemplateDoesNotExist, name + raise TemplateDoesNotExist(name) + +def find_template_source(name, dirs=None): + # For backward compatibility + import warnings + warnings.warn( + "`django.template.loaders.find_template_source` is deprecated; use `django.template.loaders.find_template` instead.", + PendingDeprecationWarning + ) + template, origin = find_template(name, dirs) + if hasattr(template, 'render'): + raise Exception("Found a compiled template that is incompatible with the deprecated `django.template.loaders.find_template_source` function.") + return template, origin def get_template(template_name): """ Returns a compiled Template object for the given template name, handling template inheritance recursively. """ - source, origin = find_template_source(template_name) - template = get_template_from_string(source, origin, template_name) + template, origin = find_template(template_name) + if not hasattr(template, 'render'): + # template needs to be compiled + template = get_template_from_string(template, origin, template_name) return template def get_template_from_string(source, origin=None, name=None): @@ -115,6 +193,6 @@ except TemplateDoesNotExist: continue # If we get here, none of the templates could be loaded - raise TemplateDoesNotExist, ', '.join(template_name_list) + raise TemplateDoesNotExist(', '.join(template_name_list)) add_to_builtins('django.template.loader_tags')