summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2014-11-19 23:23:58 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2014-11-23 11:52:12 +0100
commit29a977ab143f549c8849e9f08ca5800830eaaabb (patch)
tree27fb381958cd9e3b773d0f38a686af7c0391c2f5
parent544a716da8e2ee774dc4ae4baecfc86b07c69820 (diff)
Moved template loaders management in Engine.
Passed the engine instance to loaders. This is a prerequisite for looking up configuration on the engine instance instead of global settings. This is backwards incompatible for custom template loaders that override __init__. However the documentation doesn't talk about __init__ and the way to pass arguments to custom template loaders isn't specified. I'm considering it a private API.
-rw-r--r--django/template/engine.py49
-rw-r--r--django/template/loader.py3
-rw-r--r--django/template/loaders/base.py7
-rw-r--r--django/template/loaders/cached.py8
-rw-r--r--django/template/loaders/locmem.py3
-rw-r--r--django/template/loaders/utils.py38
-rw-r--r--django/test/signals.py7
-rw-r--r--django/views/debug.py5
-rw-r--r--tests/template_tests/test_loaders.py12
-rw-r--r--tests/template_tests/tests.py10
10 files changed, 70 insertions, 72 deletions
diff --git a/django/template/engine.py b/django/template/engine.py
index 600c74ee24..257042d497 100644
--- a/django/template/engine.py
+++ b/django/template/engine.py
@@ -2,12 +2,13 @@ import warnings
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
+from django.utils import lru_cache
+from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.functional import cached_property
-from django.utils import lru_cache
+from django.utils.module_loading import import_string
from .base import Context, Template, TemplateDoesNotExist
-from .loaders.utils import get_template_loaders
_dirs_undefined = object()
@@ -54,7 +55,49 @@ class Engine(object):
@cached_property
def template_loaders(self):
- return get_template_loaders(self.loaders)
+ return self.get_template_loaders(self.loaders)
+
+ def get_template_loaders(self, template_loaders):
+ loaders = []
+ for template_loader in template_loaders:
+ loader = self.find_template_loader(template_loader)
+ if loader is not None:
+ loaders.append(loader)
+ return loaders
+
+ def find_template_loader(self, loader):
+ if isinstance(loader, (tuple, list)):
+ args = list(loader[1:])
+ loader = loader[0]
+ else:
+ args = []
+
+ if isinstance(loader, six.string_types):
+ loader_class = import_string(loader)
+
+ if getattr(loader_class, '_accepts_engine_in_init', False):
+ args.insert(0, self)
+ else:
+ warnings.warn(
+ "%s inherits from django.template.loader.BaseLoader "
+ "instead of django.template.loaders.base.Loader. " %
+ loader, RemovedInDjango20Warning, stacklevel=2)
+
+ loader_instance = loader_class(*args)
+
+ if not loader_instance.is_usable:
+ warnings.warn(
+ "Your template loaders configuration includes %r, but "
+ "your Python installation doesn't support that type of "
+ "template loading. Consider removing that line from "
+ "your settings." % loader)
+ return None
+ else:
+ return loader_instance
+
+ else:
+ raise ImproperlyConfigured(
+ "Invalid value in template loaders configuration: %r" % loader)
def find_template(self, name, dirs=None):
# Inner import to avoid circular dependency
diff --git a/django/template/loader.py b/django/template/loader.py
index 0c24e3d373..eb89ab5900 100644
--- a/django/template/loader.py
+++ b/django/template/loader.py
@@ -48,10 +48,11 @@ from .loaders import base
class BaseLoader(base.Loader):
+ _accepts_engine_in_init = False
def __init__(self, *args, **kwargs):
warnings.warn(
- "django.template.loader.BaseLoader was renamed to "
+ "django.template.loader.BaseLoader was superseded by "
"django.template.loaders.base.Loader.",
RemovedInDjango20Warning, stacklevel=2)
super(BaseLoader, self).__init__(*args, **kwargs)
diff --git a/django/template/loaders/base.py b/django/template/loaders/base.py
index 03c58f7535..1a7df03f5e 100644
--- a/django/template/loaders/base.py
+++ b/django/template/loaders/base.py
@@ -4,10 +4,11 @@ from django.template.loader import get_template_from_string, make_origin
class Loader(object):
is_usable = False
+ # Only used to raise a deprecation warning. Remove in Django 2.0.
+ _accepts_engine_in_init = True
- def __init__(self, *args, **kwargs):
- # XXX dropping arguments silently may not be the best idea.
- pass
+ def __init__(self, engine):
+ self.engine = engine
def __call__(self, template_name, template_dirs=None):
return self.load_template(template_name, template_dirs)
diff --git a/django/template/loaders/cached.py b/django/template/loaders/cached.py
index 925abbe31f..b8cf48d237 100644
--- a/django/template/loaders/cached.py
+++ b/django/template/loaders/cached.py
@@ -9,18 +9,16 @@ from django.template.loader import get_template_from_string, make_origin
from django.utils.encoding import force_bytes
from .base import Loader as BaseLoader
-from .utils import get_template_loaders
class Loader(BaseLoader):
is_usable = True
- def __init__(self, loaders):
+ def __init__(self, engine, loaders):
self.template_cache = {}
self.find_template_cache = {}
- # Use the private, non-caching version of get_template_loaders
- # in case loaders isn't hashable.
- self.loaders = get_template_loaders(loaders)
+ self.loaders = engine.get_template_loaders(loaders)
+ super(Loader, self).__init__(engine)
def cache_key(self, template_name, template_dirs):
if template_dirs:
diff --git a/django/template/loaders/locmem.py b/django/template/loaders/locmem.py
index ba6b15ef51..3085d69258 100644
--- a/django/template/loaders/locmem.py
+++ b/django/template/loaders/locmem.py
@@ -10,8 +10,9 @@ from .base import Loader as BaseLoader
class Loader(BaseLoader):
is_usable = True
- def __init__(self, templates_dict):
+ def __init__(self, engine, templates_dict):
self.templates_dict = templates_dict
+ super(Loader, self).__init__(engine)
def load_template_source(self, template_name, template_dirs=None):
try:
diff --git a/django/template/loaders/utils.py b/django/template/loaders/utils.py
deleted file mode 100644
index 8b742f89fd..0000000000
--- a/django/template/loaders/utils.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import warnings
-
-from django.core.exceptions import ImproperlyConfigured
-from django.utils import six
-from django.utils.module_loading import import_string
-
-
-def get_template_loaders(template_loaders):
- loaders = []
- for template_loader in template_loaders:
- loader = find_template_loader(template_loader)
- if loader is not None:
- loaders.append(loader)
- return loaders
-
-
-def find_template_loader(loader):
- if isinstance(loader, (tuple, list)):
- loader, args = loader[0], loader[1:]
- else:
- args = []
-
- if isinstance(loader, six.string_types):
- loader_class = import_string(loader)
- loader_instance = loader_class(*args)
-
- if not loader_instance.is_usable:
- 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 loader_instance
-
- else:
- raise ImproperlyConfigured(
- "Invalid value in TEMPLATE_LOADERS: %r" % loader)
diff --git a/django/test/signals.py b/django/test/signals.py
index 013d293203..648162b8ae 100644
--- a/django/test/signals.py
+++ b/django/test/signals.py
@@ -98,13 +98,6 @@ def clear_context_processors_cache(**kwargs):
@receiver(setting_changed)
-def clear_template_loaders_cache(**kwargs):
- if kwargs['setting'] == 'TEMPLATE_LOADERS':
- from django.template.loaders.utils import get_template_loaders
- get_template_loaders.cache_clear()
-
-
-@receiver(setting_changed)
def clear_serializers_cache(**kwargs):
if kwargs['setting'] == 'SERIALIZATION_MODULES':
from django.core import serializers
diff --git a/django/views/debug.py b/django/views/debug.py
index 06a27069f6..ab32d866a5 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -12,7 +12,7 @@ from django.http import (HttpResponse, HttpResponseNotFound, HttpRequest,
build_request_repr)
from django.template import Template, Context, TemplateDoesNotExist
from django.template.defaultfilters import force_escape, pprint
-from django.template.loaders.utils import get_template_loaders
+from django.template.engine import Engine
from django.utils.datastructures import MultiValueDict
from django.utils.html import escape
from django.utils.encoding import force_bytes, smart_text
@@ -282,7 +282,8 @@ class ExceptionReporter(object):
# If Django fails in get_template_loaders, provide an empty list
# for the following loop to not fail.
try:
- template_loaders = get_template_loaders()
+ # TODO: handle multiple template engines.
+ template_loaders = Engine.get_default().template_loaders
except Exception:
template_loaders = []
for loader in template_loaders:
diff --git a/tests/template_tests/test_loaders.py b/tests/template_tests/test_loaders.py
index 220f766077..66957dc90e 100644
--- a/tests/template_tests/test_loaders.py
+++ b/tests/template_tests/test_loaders.py
@@ -22,7 +22,7 @@ except ImportError:
from django.template import TemplateDoesNotExist, Context
from django.template.loaders.eggs import Loader as EggLoader
-from django.template.loaders.utils import find_template_loader
+from django.template.engine import Engine
from django.template import loader
from django.test import TestCase, override_settings
from django.test.utils import IgnorePendingDeprecationWarningsMixin
@@ -86,26 +86,26 @@ class EggLoaderTest(TestCase):
@override_settings(INSTALLED_APPS=['egg_empty'])
def test_empty(self):
"Loading any template on an empty egg should fail"
- egg_loader = EggLoader()
+ egg_loader = EggLoader(Engine.get_default())
self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html")
@override_settings(INSTALLED_APPS=['egg_1'])
def test_non_existing(self):
"Template loading fails if the template is not in the egg"
- egg_loader = EggLoader()
+ egg_loader = EggLoader(Engine.get_default())
self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html")
@override_settings(INSTALLED_APPS=['egg_1'])
def test_existing(self):
"A template can be loaded from an egg"
- egg_loader = EggLoader()
+ egg_loader = EggLoader(Engine.get_default())
contents, template_name = egg_loader.load_template_source("y.html")
self.assertEqual(contents, "y")
self.assertEqual(template_name, "egg:egg_1:templates/y.html")
def test_not_installed(self):
"Loading an existent template from an egg not included in any app should fail"
- egg_loader = EggLoader()
+ egg_loader = EggLoader(Engine.get_default())
self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "y.html")
@@ -129,7 +129,7 @@ class CachedLoader(TestCase):
def test_missing_template_is_cached(self):
"#19949 -- Check that the missing template is cached."
- template_loader = find_template_loader(settings.TEMPLATE_LOADERS[0])
+ template_loader = Engine.get_default().template_loaders[0]
# Empty cache, which may be filled from previous tests.
template_loader.reset()
# Check that 'missing.html' isn't already in cache before 'missing.html' is loaded
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
index 80d7b727d6..397c6c4e11 100644
--- a/tests/template_tests/tests.py
+++ b/tests/template_tests/tests.py
@@ -14,8 +14,8 @@ from django.contrib.auth.models import Group
from django.core import urlresolvers
from django.template import (base as template_base, loader, Context,
RequestContext, Template, TemplateSyntaxError)
+from django.template.engine import Engine
from django.template.loaders import app_directories, filesystem
-from django.template.loaders.utils import get_template_loaders
from django.test import RequestFactory, TestCase
from django.test.utils import override_settings, extend_sys_path
from django.utils.deprecation import RemovedInDjango19Warning, RemovedInDjango20Warning
@@ -160,8 +160,8 @@ class UTF8Class:
class TemplateLoaderTests(TestCase):
def test_loaders_security(self):
- ad_loader = app_directories.Loader()
- fs_loader = filesystem.Loader()
+ ad_loader = app_directories.Loader(Engine.get_default())
+ fs_loader = filesystem.Loader(Engine.get_default())
def test_template_sources(path, template_dirs, expected_sources):
if isinstance(expected_sources, list):
@@ -620,9 +620,7 @@ class TemplateTests(TestCase):
if output != result:
failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Expected %r, got %r" % (is_cached, invalid_str, template_debug, name, result, output))
- # This relies on get_template_loaders() memoizing its
- # result. All callers get the same iterable of loaders.
- get_template_loaders()[0].reset()
+ Engine.get_default().template_loaders[0].reset()
if template_base.invalid_var_format_string:
expected_invalid_str = 'INVALID'