web/lib/django/template/loader.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
--- 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')