diff --git a/django/contrib/auth/tests/settings.py b/django/contrib/auth/tests/settings.py new file mode 100644 index 0000000000..7697558387 --- /dev/null +++ b/django/contrib/auth/tests/settings.py @@ -0,0 +1,26 @@ +import os + +from django.utils._os import upath + + +AUTH_MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', +) + +AUTH_TEMPLATES = [{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(os.path.dirname(upath(__file__)), 'templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': ( + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + ), + }, +}] diff --git a/django/contrib/auth/tests/test_context_processors.py b/django/contrib/auth/tests/test_context_processors.py index cb96bf5d6d..f96eac9db7 100644 --- a/django/contrib/auth/tests/test_context_processors.py +++ b/django/contrib/auth/tests/test_context_processors.py @@ -1,13 +1,12 @@ -import os - from django.contrib.auth import authenticate -from django.contrib.auth.tests.utils import skipIfCustomUser from django.contrib.auth.models import User, Permission from django.contrib.contenttypes.models import ContentType from django.contrib.auth.context_processors import PermWrapper, PermLookupDict from django.db.models import Q from django.test import TestCase, override_settings -from django.utils._os import upath + +from .settings import AUTH_MIDDLEWARE_CLASSES, AUTH_TEMPLATES +from .utils import skipIfCustomUser class MockUser(object): @@ -61,17 +60,10 @@ class PermWrapperTests(TestCase): @skipIfCustomUser @override_settings( - TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader',), - TEMPLATE_DIRS=( - os.path.join(os.path.dirname(upath(__file__)), 'templates'), - ), - TEMPLATE_CONTEXT_PROCESSORS=( - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages' - ), - ROOT_URLCONF='django.contrib.auth.tests.urls', - USE_TZ=False, # required for loading the fixture PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), + ROOT_URLCONF='django.contrib.auth.tests.urls', + TEMPLATES=AUTH_TEMPLATES, + USE_TZ=False, # required for loading the fixture ) class AuthContextProcessorTests(TestCase): """ @@ -79,12 +71,7 @@ class AuthContextProcessorTests(TestCase): """ fixtures = ['context-processors-users.xml'] - @override_settings( - MIDDLEWARE_CLASSES=( - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - ), - ) + @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES) def test_session_not_accessed(self): """ Tests that the session is not accessed simply by including @@ -93,12 +80,7 @@ class AuthContextProcessorTests(TestCase): response = self.client.get('/auth_processor_no_attr_access/') self.assertContains(response, "Session not accessed") - @override_settings( - MIDDLEWARE_CLASSES=( - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - ), - ) + @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES) def test_session_is_accessed(self): """ Tests that the session is accessed if the auth context processor diff --git a/django/contrib/auth/tests/test_forms.py b/django/contrib/auth/tests/test_forms.py index 0c13e8af74..93ce9ad073 100644 --- a/django/contrib/auth/tests/test_forms.py +++ b/django/contrib/auth/tests/test_forms.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals -import os import re from django import forms @@ -8,17 +7,18 @@ from django.contrib.auth.models import User from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm, ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget) -from django.contrib.auth.tests.utils import skipIfCustomUser from django.core import mail from django.core.mail import EmailMultiAlternatives from django.forms.fields import Field, CharField from django.test import TestCase, override_settings from django.utils.encoding import force_text -from django.utils._os import upath from django.utils import translation from django.utils.text import capfirst from django.utils.translation import ugettext as _ +from .settings import AUTH_TEMPLATES +from .utils import skipIfCustomUser + @skipIfCustomUser @override_settings(USE_TZ=False, PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) @@ -360,10 +360,7 @@ class UserChangeFormTest(TestCase): @skipIfCustomUser @override_settings( PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), - TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader',), - TEMPLATE_DIRS=( - os.path.join(os.path.dirname(upath(__file__)), 'templates'), - ), + TEMPLATES=AUTH_TEMPLATES, USE_TZ=False, ) class PasswordResetFormTest(TestCase): @@ -416,33 +413,31 @@ class PasswordResetFormTest(TestCase): self.assertEqual(mail.outbox[0].subject, 'Custom password reset on example.com') def test_custom_email_constructor(self): - template_path = os.path.join(os.path.dirname(__file__), 'templates') - with self.settings(TEMPLATE_DIRS=(template_path,)): - data = {'email': 'testclient@example.com'} + data = {'email': 'testclient@example.com'} - class CustomEmailPasswordResetForm(PasswordResetForm): - def send_mail(self, subject_template_name, email_template_name, - context, from_email, to_email, - html_email_template_name=None): - EmailMultiAlternatives( - "Forgot your password?", - "Sorry to hear you forgot your password.", - None, [to_email], - ['site_monitor@example.com'], - headers={'Reply-To': 'webmaster@example.com'}, - alternatives=[("Really sorry to hear you forgot your password.", - "text/html")]).send() + class CustomEmailPasswordResetForm(PasswordResetForm): + def send_mail(self, subject_template_name, email_template_name, + context, from_email, to_email, + html_email_template_name=None): + EmailMultiAlternatives( + "Forgot your password?", + "Sorry to hear you forgot your password.", + None, [to_email], + ['site_monitor@example.com'], + headers={'Reply-To': 'webmaster@example.com'}, + alternatives=[("Really sorry to hear you forgot your password.", + "text/html")]).send() - form = CustomEmailPasswordResetForm(data) - self.assertTrue(form.is_valid()) - # Since we're not providing a request object, we must provide a - # domain_override to prevent the save operation from failing in the - # potential case where contrib.sites is not installed. Refs #16412. - form.save(domain_override='example.com') - self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].subject, 'Forgot your password?') - self.assertEqual(mail.outbox[0].bcc, ['site_monitor@example.com']) - self.assertEqual(mail.outbox[0].content_subtype, "plain") + form = CustomEmailPasswordResetForm(data) + self.assertTrue(form.is_valid()) + # Since we're not providing a request object, we must provide a + # domain_override to prevent the save operation from failing in the + # potential case where contrib.sites is not installed. Refs #16412. + form.save(domain_override='example.com') + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].subject, 'Forgot your password?') + self.assertEqual(mail.outbox[0].bcc, ['site_monitor@example.com']) + self.assertEqual(mail.outbox[0].content_subtype, "plain") def test_preserve_username_case(self): """ diff --git a/django/contrib/auth/tests/test_views.py b/django/contrib/auth/tests/test_views.py index 251af54ec8..b28615374c 100644 --- a/django/contrib/auth/tests/test_views.py +++ b/django/contrib/auth/tests/test_views.py @@ -1,14 +1,17 @@ from importlib import import_module import itertools -import os import re import warnings from django.apps import apps -from django.conf import global_settings, settings +from django.conf import settings from django.contrib.sites.requests import RequestSite from django.contrib.admin.models import LogEntry +from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME +from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm, + SetPasswordForm) from django.contrib.auth.models import User +from django.contrib.auth.views import login as login_view from django.core import mail from django.core.urlresolvers import reverse, NoReverseMatch from django.http import QueryDict, HttpRequest @@ -16,19 +19,15 @@ from django.utils.encoding import force_text from django.utils.http import urlquote from django.utils.six.moves.urllib.parse import urlparse, ParseResult from django.utils.translation import LANGUAGE_SESSION_KEY -from django.utils._os import upath from django.test import TestCase, override_settings from django.test.utils import patch_logger from django.middleware.csrf import CsrfViewMiddleware from django.contrib.sessions.middleware import SessionMiddleware -from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME -from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm, - SetPasswordForm) # Needed so model is installed when tests are run independently: -from django.contrib.auth.tests.custom_user import CustomUser # NOQA -from django.contrib.auth.tests.utils import skipIfCustomUser -from django.contrib.auth.views import login as login_view +from .custom_user import CustomUser # NOQA +from .settings import AUTH_TEMPLATES +from .utils import skipIfCustomUser @override_settings( @@ -36,10 +35,7 @@ from django.contrib.auth.views import login as login_view ('en', 'English'), ), LANGUAGE_CODE='en', - TEMPLATE_LOADERS=global_settings.TEMPLATE_LOADERS, - TEMPLATE_DIRS=( - os.path.join(os.path.dirname(upath(__file__)), 'templates'), - ), + TEMPLATES=AUTH_TEMPLATES, USE_TZ=False, PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), ROOT_URLCONF='django.contrib.auth.tests.urls', diff --git a/django/views/debug.py b/django/views/debug.py index 09cc5c462e..b0392c1a6d 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -781,7 +781,7 @@ TECHNICAL_500_TEMPLATE = (""" {% endfor %} {% else %} -

Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!

+

Django couldn't find any templates because your 'loaders' option is empty!

{% endif %} {% endif %} @@ -900,7 +900,7 @@ Installed Middleware: {% for loader in loader_debug_info %}Using loader {{ loader.loader }}: {% for t in loader.templates %}{{ t.name }} ({{ t.status }}) {% endfor %}{% endfor %} -{% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty! +{% else %}Django couldn't find any templates because your 'loaders' option is empty! {% endif %} {% endif %}{% if template_info %} Template error: @@ -1091,7 +1091,7 @@ Installed Middleware: {% for loader in loader_debug_info %}Using loader {{ loader.loader }}: {% for t in loader.templates %}{{ t.name }} ({{ t.status }}) {% endfor %}{% endfor %} -{% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty! +{% else %}Django couldn't find any templates because your 'loaders' option is empty! {% endif %} {% endif %}{% if template_info %} Template error: diff --git a/docs/howto/deployment/checklist.txt b/docs/howto/deployment/checklist.txt index 24b33adc35..e4b434714e 100644 --- a/docs/howto/deployment/checklist.txt +++ b/docs/howto/deployment/checklist.txt @@ -178,8 +178,8 @@ processing time. This helps a lot on virtualized hosts with limited network performance. -:setting:`TEMPLATE_LOADERS` ---------------------------- +:setting:`TEMPLATES` +-------------------- Enabling the cached template loader often improves performance drastically, as it avoids compiling each template every time it needs to be rendered. See the diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 415b61eafd..f3d50d3c90 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -90,6 +90,7 @@ details on these changes. * The following settings will be removed: * ``ALLOWED_INCLUDE_ROOTS`` + * ``TEMPLATE_LOADERS`` * ``TEMPLATE_STRING_IF_INVALID`` * The backwards compatibility alias ``django.template.loader.BaseLoader`` will diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index b428c9afb8..c4590abf23 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -314,12 +314,13 @@ creating a template that the view can use. First, create a directory called ``templates`` in your ``polls`` directory. Django will look for templates in there. -Django's :setting:`TEMPLATE_LOADERS` setting contains a list of callables that -know how to import templates from various sources. One of the defaults is -:class:`django.template.loaders.app_directories.Loader` which looks for a -"templates" subdirectory in each of the :setting:`INSTALLED_APPS` - this is how -Django knows to find the polls templates even though we didn't modify -:setting:`TEMPLATE_DIRS`, as we did in :ref:`Tutorial 2 +Your project's :setting:`TEMPLATES` setting describes how Django will load and +render templates. The default settings file configures a ``DjangoTemplates`` +backend whose :setting:`APP_DIRS ` option is set to +``True``. By convention ``DjangoTemplates`` looks for a "templates" +subdirectory in each of the :setting:`INSTALLED_APPS`. This is how Django +knows to find the polls templates even though we didn't modify the +:setting:`DIRS ` option, as we did in :ref:`Tutorial 2 `. .. admonition:: Organizing templates diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index a6a315cc88..55dfe08f17 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2337,8 +2337,9 @@ directory. In order to override one or more of them, first create an ``admin`` directory in your project's ``templates`` directory. This can be any of the directories -you specified in :setting:`TEMPLATE_DIRS`. If you have customized the -:setting:`TEMPLATE_LOADERS` setting, be sure +you specified in the :setting:`DIRS ` option of the +``DjangoTemplates`` backend in the :setting:`TEMPLATES` setting. If you have +customized the ``'loaders'`` option, be sure ``'django.template.loaders.filesystem.Loader'`` appears before ``'django.template.loaders.app_directories.Loader'`` so that your custom templates will be found by the template loading system before those that are diff --git a/docs/ref/contrib/sitemaps.txt b/docs/ref/contrib/sitemaps.txt index 8279d8e93e..b28b9b463d 100644 --- a/docs/ref/contrib/sitemaps.txt +++ b/docs/ref/contrib/sitemaps.txt @@ -34,9 +34,9 @@ To install the sitemap app, follow these steps: 1. Add ``'django.contrib.sitemaps'`` to your :setting:`INSTALLED_APPS` setting. -2. Make sure ``'django.template.loaders.app_directories.Loader'`` - is in your :setting:`TEMPLATE_LOADERS` setting. It's in there by default, - so you'll only need to change this if you've changed that setting. +2. Make sure your :setting:`TEMPLATES` setting contains a ``DjangoTemplates`` + backend whose ``APP_DIRS`` options is set to ``True``. It's in there by + default, so you'll only need to change this if you've changed that setting. 3. Make sure you've installed the :mod:`sites framework `. diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index dd01e9e1cd..ae387023e7 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -2439,6 +2439,11 @@ Default:: ('django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader') +.. deprecated:: 1.8 + + Set the ``'loaders'`` option in the :setting:`OPTIONS ` + of a ``DjangoTemplates`` backend instead. + A tuple of template loader classes, specified as strings. Each ``Loader`` class knows how to import templates from a particular source. Optionally, a tuple can be used instead of a string. The first item in the tuple should be the ``Loader``’s diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt index 5aacb2bc09..7ab29ab276 100644 --- a/docs/ref/templates/api.txt +++ b/docs/ref/templates/api.txt @@ -734,9 +734,10 @@ with a few other template loaders, which know how to load templates from other sources. Some of these other loaders are disabled by default, but you can activate them -by editing your :setting:`TEMPLATE_LOADERS` setting. :setting:`TEMPLATE_LOADERS` -should be a tuple of strings or tuples, where each represents a template loader -class. Here are the template loaders that come with Django: +by adding a ``'loaders'`` option to your ``DjangoTemplates`` backend in the +:setting:`TEMPLATES` setting. ``'loaders'`` should be a list of strings or +tuples, where each represents a template loader class. Here are the template +loaders that come with Django: .. currentmodule:: django.template.loaders @@ -744,8 +745,16 @@ class. Here are the template loaders that come with Django: .. class:: filesystem.Loader - Loads templates from the filesystem, according to :setting:`TEMPLATE_DIRS`. - This loader is enabled by default. + Loads templates from the filesystem, according to + :setting:`DIRS `. + + This loader is enabled by default. However it won't find any templates + until you set :setting:`DIRS ` to a non-empty list:: + + TEMPLATES = [{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')], + }] ``django.template.loaders.app_directories.Loader`` @@ -782,7 +791,14 @@ class. Here are the template loaders that come with Django: it caches a list of which :setting:`INSTALLED_APPS` packages have a ``templates`` subdirectory. - This loader is enabled by default. + This loader is enabled if and only if :setting:`APP_DIRS + ` is set:: + + TEMPLATES = [{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + }] + ``django.template.loaders.eggs.Loader`` @@ -810,12 +826,18 @@ class. Here are the template loaders that come with Django: For example, to enable template caching with the ``filesystem`` and ``app_directories`` template loaders you might use the following settings:: - TEMPLATE_LOADERS = ( - ('django.template.loaders.cached.Loader', ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - )), - ) + TEMPLATES = [{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')], + 'OPTIONS': { + 'loaders': [ + ('django.template.loaders.cached.Loader', ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + )), + ], + }, + }] .. note:: @@ -838,17 +860,21 @@ class. Here are the template loaders that come with Django: This loader takes a dictionary of templates as its first argument:: - TEMPLATE_LOADERS = ( - ('django.template.loaders.locmem.Loader', { - 'index.html': 'content here', - }), - ) + TEMPLATES = [{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'loaders': [ + ('django.template.loaders.locmem.Loader', { + 'index.html': 'content here', + }), + ], + }, + }] This loader is disabled by default. -Django uses the template loaders in order according to the -:setting:`TEMPLATE_LOADERS` setting. It uses each loader until a loader finds a -match. +Django uses the template loaders in order according to the ``'loaders'`` +option. It uses each loader until a loader finds a match. .. currentmodule:: django.template diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt index 422dff10e5..6d06fa49b2 100644 --- a/docs/releases/1.2.txt +++ b/docs/releases/1.2.txt @@ -267,9 +267,9 @@ opposed to functions, the only method available until Django 1.1. All the template loaders :ref:`shipped with Django ` have been ported to the new API but they still implement the function-based API and the template core machinery still accepts function-based loaders (builtin or -third party) so there is no immediate need to modify your -:setting:`TEMPLATE_LOADERS` setting in existing projects, things will keep -working if you leave it untouched up to and including the Django 1.3 release. +third party) so there is no immediate need to modify your ``TEMPLATE_LOADERS`` +setting in existing projects, things will keep working if you leave it +untouched up to and including the Django 1.3 release. If you have developed your own custom template loaders we suggest to consider porting them to a class-based implementation because the code for backwards diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index d43ab2e51b..0cc074b24b 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -917,7 +917,7 @@ Miscellaneous session store always fetches the most current session data. * Private APIs ``override_template_loaders`` and ``override_with_test_loader`` - in ``django.test.utils`` were removed. Override ``TEMPLATE_LOADERS`` with + in ``django.test.utils`` were removed. Override ``TEMPLATES`` with ``override_settings`` instead. * Warnings from the MySQL database backend are no longer converted to @@ -1021,6 +1021,7 @@ As a consequence of the multiple template engines refactor, several settings are deprecated in favor of :setting:`TEMPLATES`: * ``ALLOWED_INCLUDE_ROOTS`` +* ``TEMPLATE_LOADERS`` * ``TEMPLATE_STRING_IF_INVALID`` ``django.core.context_processors`` diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt index ee2d583dc7..f3d922ab3a 100644 --- a/docs/topics/class-based-views/generic-display.txt +++ b/docs/topics/class-based-views/generic-display.txt @@ -136,10 +136,9 @@ bit is just the lowercased version of the model's name. .. note:: - Thus, when (for example) the - :class:`django.template.loaders.app_directories.Loader` template loader is - enabled in :setting:`TEMPLATE_LOADERS`, a template location could be: - /path/to/project/books/templates/books/publisher_list.html + Thus, when (for example) the ``APP_DIRS`` option of a ``DjangoTemplates`` + backend is set to True in :setting:`TEMPLATES`, a template location could + be: /path/to/project/books/templates/books/publisher_list.html This template will be rendered against a context containing a variable called ``object_list`` that contains all the publisher objects. A very simple template diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt index d1e06704f2..b986ca2481 100644 --- a/docs/topics/testing/tools.txt +++ b/docs/topics/testing/tools.txt @@ -1303,8 +1303,7 @@ Django itself uses this signal to reset various data: Overridden settings Data reset ================================ ======================== USE_TZ, TIME_ZONE Databases timezone -TEMPLATE_CONTEXT_PROCESSORS Context processors cache -TEMPLATE_LOADERS Template loaders cache +TEMPLATES Template engines SERIALIZATION_MODULES Serializers cache LOCALE_PATHS, LANGUAGE_CODE Default translation and loaded translations MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py index c87f6b6204..f1a43763b6 100644 --- a/tests/settings_tests/tests.py +++ b/tests/settings_tests/tests.py @@ -431,14 +431,14 @@ class IsOverriddenTest(TestCase): s = Settings('fake_settings_module') self.assertTrue(s.is_overridden('SECRET_KEY')) - self.assertFalse(s.is_overridden('TEMPLATE_LOADERS')) + self.assertFalse(s.is_overridden('ALLOWED_HOSTS')) finally: del sys.modules['fake_settings_module'] def test_override(self): - self.assertFalse(settings.is_overridden('TEMPLATE_LOADERS')) - with override_settings(TEMPLATE_LOADERS=[]): - self.assertTrue(settings.is_overridden('TEMPLATE_LOADERS')) + self.assertFalse(settings.is_overridden('ALLOWED_HOSTS')) + with override_settings(ALLOWED_HOSTS=[]): + self.assertTrue(settings.is_overridden('ALLOWED_HOSTS')) class TestTupleSettings(unittest.TestCase): diff --git a/tests/template_tests/test_loaders.py b/tests/template_tests/test_loaders.py index 14390c3f46..47e69ad3c5 100644 --- a/tests/template_tests/test_loaders.py +++ b/tests/template_tests/test_loaders.py @@ -16,7 +16,7 @@ except ImportError: from django.template import TemplateDoesNotExist, Context -from django.template.loaders.eggs import Loader as EggLoader +from django.template.loaders import cached, eggs from django.template.engine import Engine from django.template import loader from django.test import SimpleTestCase, override_settings @@ -26,6 +26,11 @@ from django.utils._os import upath from django.utils.six import StringIO +TEMPLATES_DIR = os.path.join(os.path.dirname(upath(__file__)), 'templates') + +GLOBAL_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.dirname(upath(__file__))), 'templates') + + # Mock classes and objects for pkg_resources functions. class MockLoader(object): pass @@ -48,7 +53,10 @@ def create_egg(name, resources): @unittest.skipUnless(pkg_resources, 'setuptools is not installed') class EggLoaderTest(SimpleTestCase): + def setUp(self): + self.loader = eggs.Loader(Engine.get_default()) + # Defined here b/c at module scope we may not have pkg_resources class MockProvider(pkg_resources.NullProvider): def __init__(self, module): @@ -81,70 +89,64 @@ class EggLoaderTest(SimpleTestCase): @override_settings(INSTALLED_APPS=['egg_empty']) def test_empty(self): "Loading any template on an empty egg should fail" - egg_loader = EggLoader(Engine.get_default()) - self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") + with self.assertRaises(TemplateDoesNotExist): + self.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(Engine.get_default()) - self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") + with self.assertRaises(TemplateDoesNotExist): + self.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(Engine.get_default()) - contents, template_name = egg_loader.load_template_source("y.html") + contents, template_name = self.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(Engine.get_default()) - self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "y.html") + with self.assertRaises(TemplateDoesNotExist): + self.loader.load_template_source("y.html") -@override_settings( - TEMPLATE_LOADERS=( - ('django.template.loaders.cached.Loader', ( - 'django.template.loaders.filesystem.Loader', - )), - ) -) class CachedLoader(SimpleTestCase): + + def setUp(self): + self.loader = cached.Loader(Engine.get_default(), [ + 'django.template.loaders.filesystem.Loader', + ]) + def test_templatedir_caching(self): "Check that the template directories form part of the template cache key. Refs #13573" - template_loader = Engine.get_default().template_loaders[0] - # Retrieve a template specifying a template directory to check - t1, name = template_loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'first'),)) + t1, name = self.loader.find_template('test.html', (os.path.join(TEMPLATES_DIR, 'first'),)) # Now retrieve the same template name, but from a different directory - t2, name = template_loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'second'),)) + t2, name = self.loader.find_template('test.html', (os.path.join(TEMPLATES_DIR, 'second'),)) # The two templates should not have the same content self.assertNotEqual(t1.render(Context({})), t2.render(Context({}))) def test_missing_template_is_cached(self): "#19949 -- Check that the missing template is cached." - 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 - self.assertRaises(KeyError, lambda: template_loader.template_cache["missing.html"]) + with self.assertRaises(KeyError): + self.loader.template_cache["missing.html"] # Try to load it, it should fail - self.assertRaises(TemplateDoesNotExist, template_loader.load_template, "missing.html") + with self.assertRaises(TemplateDoesNotExist): + self.loader.load_template("missing.html") # Verify that the fact that the missing template, which hasn't been found, has actually # been cached: - self.assertEqual(template_loader.template_cache.get("missing.html"), - TemplateDoesNotExist, + cached_miss = self.loader.template_cache["missing.html"] + self.assertEqual(cached_miss, TemplateDoesNotExist, "Cached template loader doesn't cache file lookup misses. It should.") -@override_settings( - TEMPLATE_DIRS=( - os.path.join(os.path.dirname(upath(__file__)), 'templates'), - ) -) +@override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [TEMPLATES_DIR], +}]) class RenderToStringTest(SimpleTestCase): def test_basic(self): self.assertEqual(loader.render_to_string('test_context.html'), 'obj:\n') @@ -164,11 +166,10 @@ class RenderToStringTest(SimpleTestCase): loader.select_template, []) -@override_settings( - TEMPLATE_DIRS=( - os.path.join(os.path.dirname(upath(__file__)), 'templates'), - ) -) +@override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [TEMPLATES_DIR], +}]) class DeprecatedRenderToStringTest(IgnorePendingDeprecationWarningsMixin, SimpleTestCase): def test_existing_context_kept_clean(self): @@ -191,7 +192,10 @@ class DeprecatedRenderToStringTest(IgnorePendingDeprecationWarningsMixin, Simple loader.render_to_string('test_context_stack.html', context_instance=Context()).strip()) -class TemplateDirsOverrideTest(IgnorePendingDeprecationWarningsMixin, unittest.TestCase): +@override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', +}]) +class TemplateDirsOverrideTest(IgnorePendingDeprecationWarningsMixin, SimpleTestCase): dirs_tuple = (os.path.join(os.path.dirname(upath(__file__)), 'other_templates'),) dirs_list = list(dirs_tuple) @@ -212,14 +216,18 @@ class TemplateDirsOverrideTest(IgnorePendingDeprecationWarningsMixin, unittest.T self.assertEqual(template.render(Context({})), 'spam eggs\n') -@override_settings( - TEMPLATE_LOADERS=( - ('django.template.loaders.cached.Loader', ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - )), - ) -) +@override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [GLOBAL_TEMPLATES_DIR], + 'OPTIONS': { + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ]), + ], + }, +}]) class PriorityCacheLoader(SimpleTestCase): def test_basic(self): """ @@ -229,10 +237,16 @@ class PriorityCacheLoader(SimpleTestCase): self.assertEqual(t1.render(Context({})), 'priority\n') -@override_settings( - TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader',), -) +@override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [GLOBAL_TEMPLATES_DIR], + 'OPTIONS': { + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ], + }, +}]) class PriorityLoader(SimpleTestCase): def test_basic(self): """ diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index 5128fd64d5..876df43aa4 100644 --- a/tests/template_tests/tests.py +++ b/tests/template_tests/tests.py @@ -17,6 +17,11 @@ from django.test.utils import override_settings, extend_sys_path from django.utils._os import upath +TESTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(upath(__file__)))) + +TEMPLATES_DIR = os.path.join(TESTS_DIR, 'templates') + + class TemplateLoaderTests(SimpleTestCase): def test_loaders_security(self): @@ -73,7 +78,10 @@ class TemplateLoaderTests(SimpleTestCase): test_template_sources('/DIR1/index.HTML', template_dirs, ['/DIR1/index.HTML']) - @override_settings(TEMPLATE_LOADERS=['django.template.loaders.filesystem.Loader']) + @override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [TEMPLATES_DIR], + }]) # Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with # the compiled templates. @override_settings(TEMPLATE_DEBUG=True) @@ -90,10 +98,17 @@ class TemplateLoaderTests(SimpleTestCase): self.assertTrue(template_name.endswith(load_name), 'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name) - @override_settings(TEMPLATE_LOADERS=[ - ('django.template.loaders.cached.Loader', - ['django.template.loaders.filesystem.Loader']), - ]) + @override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [TEMPLATES_DIR], + 'OPTIONS': { + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.filesystem.Loader', + ]), + ], + }, + }]) @override_settings(TEMPLATE_DEBUG=True) def test_cached_loader_debug_origin(self): # Same comment as in test_loader_debug_origin. @@ -130,7 +145,10 @@ class TemplateLoaderTests(SimpleTestCase): # Test the base loader class via the app loader. load_template # from base is used by all shipped loaders excepting cached, # which has its own test. - @override_settings(TEMPLATE_LOADERS=['django.template.loaders.app_directories.Loader']) + @override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + }]) def test_include_missing_template(self): """ Tests that the correct template is identified as not existing @@ -151,7 +169,10 @@ class TemplateLoaderTests(SimpleTestCase): # Test the base loader class via the app loader. load_template # from base is used by all shipped loaders excepting cached, # which has its own test. - @override_settings(TEMPLATE_LOADERS=['django.template.loaders.app_directories.Loader']) + @override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + }]) def test_extends_include_missing_baseloader(self): """ Tests that the correct template is identified as not existing @@ -168,34 +189,39 @@ class TemplateLoaderTests(SimpleTestCase): self.assertEqual(e.args[0], 'missing.html') self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) + @override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.app_directories.Loader', + ]), + ], + }, + }]) @override_settings(TEMPLATE_DEBUG=True) def test_extends_include_missing_cachedloader(self): """ Same as test_extends_include_missing_baseloader, only tests behavior of the cached loader instead of base loader. """ - with override_settings(TEMPLATE_LOADERS=[ - ('django.template.loaders.cached.Loader', [ - 'django.template.loaders.app_directories.Loader', - ]), - ]): - load_name = 'test_extends_error.html' - tmpl = loader.get_template(load_name) - r = None - try: - r = tmpl.render(template.Context({})) - except template.TemplateDoesNotExist as e: - self.assertEqual(e.args[0], 'missing.html') - self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) + load_name = 'test_extends_error.html' + tmpl = loader.get_template(load_name) + r = None + try: + r = tmpl.render(template.Context({})) + except template.TemplateDoesNotExist as e: + self.assertEqual(e.args[0], 'missing.html') + self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) - # For the cached loader, repeat the test, to ensure the first attempt did not cache a - # result that behaves incorrectly on subsequent attempts. - tmpl = loader.get_template(load_name) - try: - tmpl.render(template.Context({})) - except template.TemplateDoesNotExist as e: - self.assertEqual(e.args[0], 'missing.html') - self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) + # For the cached loader, repeat the test, to ensure the first attempt did not cache a + # result that behaves incorrectly on subsequent attempts. + tmpl = loader.get_template(load_name) + try: + tmpl.render(template.Context({})) + except template.TemplateDoesNotExist as e: + self.assertEqual(e.args[0], 'missing.html') + self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) def test_include_template_argument(self): """ @@ -429,11 +455,16 @@ class RequestContextTests(unittest.TestCase): def setUp(self): self.fake_request = RequestFactory().get('/') - @override_settings(TEMPLATE_LOADERS=[ - ('django.template.loaders.locmem.Loader', { - 'child': '{{ var|default:"none" }}', - }), - ]) + @override_settings(TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'loaders': [ + ('django.template.loaders.locmem.Loader', { + 'child': '{{ var|default:"none" }}', + }), + ], + }, + }]) def test_include_only(self): """ Regression test for #15721, ``{% include %}`` and ``RequestContext`` diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index b9987c72b0..ab04c6622d 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -63,21 +63,28 @@ class DebugViewTests(TestCase): response = self.client.get('/raises400/') self.assertContains(response, '