diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 05c37b0f13..e154c9299a 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -309,12 +309,17 @@ def missing_docutils_page(request): def load_all_installed_template_libraries(): # Load/register all template tag libraries from installed apps. - for e in templatetags.__path__: - libraries = [os.path.splitext(p)[0] for p in os.listdir(e) if p.endswith('.py') and p[0].isalpha()] + for module_name in template.get_templatetags_modules(): + mod = import_module(module_name) + libraries = [ + os.path.splitext(p)[0] + for p in os.listdir(os.path.dirname(mod.__file__)) + if p.endswith('.py') and p[0].isalpha() + ] for library_name in libraries: try: - lib = template.get_library("django.templatetags.%s" % library_name.split('.')[-1]) - except template.InvalidTemplateLibrary: + lib = template.get_library(library_name) + except template.InvalidTemplateLibrary, e: pass def get_return_data_type(func_name): diff --git a/django/template/__init__.py b/django/template/__init__.py index 4c386bea30..af033222a8 100644 --- a/django/template/__init__.py +++ b/django/template/__init__.py @@ -809,7 +809,7 @@ class TextNode(Node): def render(self, context): return self.s - + def _render_value_in_context(value, context): """ Converts any value to a string to become part of a rendered template. This @@ -966,22 +966,70 @@ class Library(object): return func return dec -def get_library(module_name): - lib = libraries.get(module_name, None) +def import_library(taglib_module): + """Load a template tag library module. + + Verifies that the library contains a 'register' attribute, and + returns that attribute as the representation of the library + """ + try: + mod = import_module(taglib_module) + except ImportError: + return None + try: + return mod.register + except AttributeError: + raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % taglib_module) + +templatetags_modules = [] + +def get_templatetags_modules(): + """Return the list of all available template tag modules. + + Caches the result for faster access. + """ + global templatetags_modules + if not templatetags_modules: + _templatetags_modules = [] + # Populate list once per thread. + for app_module in ['django'] + list(settings.INSTALLED_APPS): + try: + templatetag_module = '%s.templatetags' % app_module + import_module(templatetag_module) + _templatetags_modules.append(templatetag_module) + except ImportError: + continue + templatetags_modules = _templatetags_modules + return templatetags_modules + +def get_library(library_name): + """ + Load the template library module with the given name. + + If library is not already loaded loop over all templatetags modules to locate it. + + {% load somelib %} and {% load someotherlib %} loops twice. + + Subsequent loads eg. {% load somelib %} in the same process will grab the cached + module from libraries. + """ + lib = libraries.get(library_name, None) if not lib: - try: - mod = import_module(module_name) - except ImportError, e: - raise InvalidTemplateLibrary("Could not load template library from %s, %s" % (module_name, e)) - try: - lib = mod.register - libraries[module_name] = lib - except AttributeError: - raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % module_name) + templatetags_modules = get_templatetags_modules() + tried_modules = [] + for module in templatetags_modules: + taglib_module = '%s.%s' % (module, library_name) + tried_modules.append(taglib_module) + lib = import_library(taglib_module) + if lib: + libraries[library_name] = lib + break + if not lib: + raise InvalidTemplateLibrary("Template library %s not found, tried %s" % (library_name, ','.join(tried_modules))) return lib -def add_to_builtins(module_name): - builtins.append(get_library(module_name)) +def add_to_builtins(module): + builtins.append(import_library(module)) add_to_builtins('django.template.defaulttags') add_to_builtins('django.template.defaultfilters') diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index d703c6ab5e..f1b1de795b 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -920,7 +920,7 @@ def load(parser, token): for taglib in bits[1:]: # add the library to the parser try: - lib = get_library("django.templatetags.%s" % taglib) + lib = get_library(taglib) parser.add_library(lib) except InvalidTemplateLibrary, e: raise TemplateSyntaxError("'%s' is not a valid tag library: %s" % diff --git a/django/templatetags/__init__.py b/django/templatetags/__init__.py index 4033e5a8f6..e69de29bb2 100644 --- a/django/templatetags/__init__.py +++ b/django/templatetags/__init__.py @@ -1,8 +0,0 @@ -from django.conf import settings -from django.utils import importlib - -for a in settings.INSTALLED_APPS: - try: - __path__.extend(importlib.import_module('.templatetags', a).__path__) - except ImportError: - pass diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 29462086d8..88afc548dc 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -59,7 +59,7 @@ def do_echo(parser, token): register.tag("echo", do_echo) -template.libraries['django.templatetags.testtags'] = register +template.libraries['testtags'] = register ##################################### # Helper objects for template tests #