diff --git a/django/template/base.py b/django/template/base.py index 40a577dbd8..e23420b828 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -1215,6 +1215,22 @@ class Library(object): return func return dec +def is_library_missing(name): + """Check if library that failed to load cannot be found under any + templatetags directory or does exist but fails to import. + + Non-existing condition is checked recursively for each subpackage in cases + like /templatetags/subpackage/package/module.py. + """ + # Don't bother to check if '.' is in name since any name will be prefixed + # with some template root. + path, module = name.rsplit('.', 1) + try: + package = import_module(path) + return not module_has_submodule(package, module) + except ImportError: + return is_library_missing(path) + def import_library(taglib_module): """ Load a template tag library module. @@ -1222,8 +1238,6 @@ def import_library(taglib_module): Verifies that the library contains a 'register' attribute, and returns that attribute as the representation of the library """ - app_path, taglib = taglib_module.rsplit('.', 1) - app_module = import_module(app_path) try: mod = import_module(taglib_module) except ImportError, e: @@ -1231,7 +1245,7 @@ def import_library(taglib_module): # that's not an error that should be raised. If the submodule exists # and raised an ImportError on the attempt to load it, that we want # to raise. - if not module_has_submodule(app_module, taglib): + if is_library_missing(taglib_module): return None else: raise InvalidTemplateLibrary("ImportError raised loading %s: %s" % diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 20cce0093d..757629f47e 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -698,9 +698,10 @@ load Loads a custom template tag set. For example, the following template would load all the tags and filters -registered in ``somelibrary`` and ``otherlibrary``:: +registered in ``somelibrary`` and ``otherlibrary`` located in package +``package``:: - {% load somelibrary otherlibrary %} + {% load somelibrary package.otherlibrary %} .. versionchanged:: 1.3 diff --git a/tests/regressiontests/templates/templatetags/subpackage/__init__.py b/tests/regressiontests/templates/templatetags/subpackage/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/regressiontests/templates/templatetags/subpackage/echo.py b/tests/regressiontests/templates/templatetags/subpackage/echo.py new file mode 100644 index 0000000000..0e4e862887 --- /dev/null +++ b/tests/regressiontests/templates/templatetags/subpackage/echo.py @@ -0,0 +1,7 @@ +from django import template + +register = template.Library() + +@register.simple_tag +def echo2(arg): + return arg diff --git a/tests/regressiontests/templates/templatetags/subpackage/echo_invalid.py b/tests/regressiontests/templates/templatetags/subpackage/echo_invalid.py new file mode 100644 index 0000000000..c12ea65507 --- /dev/null +++ b/tests/regressiontests/templates/templatetags/subpackage/echo_invalid.py @@ -0,0 +1 @@ +import nonexistent.module diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 712093b934..e2743581ae 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -1193,17 +1193,22 @@ class Templates(unittest.TestCase): 'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'), ### LOADING TAG LIBRARIES ################################################# + 'load01': ("{% load testtags subpackage.echo %}{% echo test %} {% echo2 \"test\" %}", {}, "test test"), + 'load02': ("{% load subpackage.echo %}{% echo2 \"test\" %}", {}, "test"), # {% load %} tag, importing individual tags - 'load1': ("{% load echo from testtags %}{% echo this that theother %}", {}, 'this that theother'), - 'load2': ("{% load echo other_echo from testtags %}{% echo this that theother %} {% other_echo and another thing %}", {}, 'this that theother and another thing'), - 'load3': ("{% load echo upper from testtags %}{% echo this that theother %} {{ statement|upper }}", {'statement': 'not shouting'}, 'this that theother NOT SHOUTING'), + 'load03': ("{% load echo from testtags %}{% echo this that theother %}", {}, 'this that theother'), + 'load04': ("{% load echo other_echo from testtags %}{% echo this that theother %} {% other_echo and another thing %}", {}, 'this that theother and another thing'), + 'load05': ("{% load echo upper from testtags %}{% echo this that theother %} {{ statement|upper }}", {'statement': 'not shouting'}, 'this that theother NOT SHOUTING'), + 'load06': ("{% load echo2 from subpackage.echo %}{% echo2 \"test\" %}", {}, "test"), # {% load %} tag errors - 'load4': ("{% load echo other_echo bad_tag from testtags %}", {}, template.TemplateSyntaxError), - 'load5': ("{% load echo other_echo bad_tag from %}", {}, template.TemplateSyntaxError), - 'load6': ("{% load from testtags %}", {}, template.TemplateSyntaxError), - 'load7': ("{% load echo from bad_library %}", {}, template.TemplateSyntaxError), + 'load07': ("{% load echo other_echo bad_tag from testtags %}", {}, template.TemplateSyntaxError), + 'load08': ("{% load echo other_echo bad_tag from %}", {}, template.TemplateSyntaxError), + 'load09': ("{% load from testtags %}", {}, template.TemplateSyntaxError), + 'load10': ("{% load echo from bad_library %}", {}, template.TemplateSyntaxError), + 'load11': ("{% load subpackage.echo_invalid %}", {}, template.TemplateSyntaxError), + 'load12': ("{% load subpackage.missing %}", {}, template.TemplateSyntaxError), ### I18N ##################################################################