Fixed #21598 -- cleaned up template loader overrides in tests
- Template loader overriding is managed with contexts. - The test loader is a class (function based loaders entered deprecation timeline in 1.4). - Template loader overrider that overrides with test loader added.
This commit is contained in:
parent
756c390fb5
commit
4dc4d12e27
|
@ -146,42 +146,107 @@ def get_runner(settings, test_runner_class=None):
|
|||
return test_runner
|
||||
|
||||
|
||||
def setup_test_template_loader(templates_dict, use_cached_loader=False):
|
||||
class override_template_loaders(object):
|
||||
"""
|
||||
Changes Django to only find templates from within a dictionary (where each
|
||||
key is the template name and each value is the corresponding template
|
||||
content to return).
|
||||
Acts as a function decorator, context manager or start/end manager and
|
||||
override the template loaders. It could be used in the following ways:
|
||||
|
||||
Use meth:`restore_template_loaders` to restore the original loaders.
|
||||
@override_template_loaders(SomeLoader())
|
||||
def test_function(self):
|
||||
...
|
||||
|
||||
with override_template_loaders(SomeLoader(), OtherLoader()) as loaders:
|
||||
...
|
||||
|
||||
loaders = override_template_loaders.override(SomeLoader())
|
||||
...
|
||||
override_template_loaders.restore()
|
||||
"""
|
||||
def __init__(self, *loaders):
|
||||
self.loaders = loaders
|
||||
self.old_loaders = []
|
||||
|
||||
def __enter__(self):
|
||||
self.old_loaders = loader.template_source_loaders
|
||||
loader.template_source_loaders = self.loaders
|
||||
return self.loaders
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
loader.template_source_loaders = self.old_loaders
|
||||
|
||||
def __call__(self, test_func):
|
||||
@wraps(test_func)
|
||||
def inner(*args, **kwargs):
|
||||
with self:
|
||||
return test_func(*args, **kwargs)
|
||||
return inner
|
||||
|
||||
@classmethod
|
||||
def override(cls, *loaders):
|
||||
if hasattr(loader, RESTORE_LOADERS_ATTR):
|
||||
raise Exception("loader.%s already exists" % RESTORE_LOADERS_ATTR)
|
||||
setattr(loader, RESTORE_LOADERS_ATTR, loader.template_source_loaders)
|
||||
loader.template_source_loaders = loaders
|
||||
return loaders
|
||||
|
||||
def test_template_loader(template_name, template_dirs=None):
|
||||
@classmethod
|
||||
def restore(cls):
|
||||
loader.template_source_loaders = getattr(loader, RESTORE_LOADERS_ATTR)
|
||||
delattr(loader, RESTORE_LOADERS_ATTR)
|
||||
|
||||
|
||||
class TestTemplateLoader(loader.BaseLoader):
|
||||
"A custom template loader that loads templates from a dictionary."
|
||||
is_usable = True
|
||||
|
||||
def __init__(self, templates_dict):
|
||||
self.templates_dict = templates_dict
|
||||
|
||||
def load_template_source(self, template_name, template_dirs=None,
|
||||
skip_template=None):
|
||||
try:
|
||||
return (templates_dict[template_name], "test:%s" % template_name)
|
||||
return (self.templates_dict[template_name],
|
||||
"test:%s" % template_name)
|
||||
except KeyError:
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
|
||||
|
||||
class override_with_test_loader(override_template_loaders):
|
||||
"""
|
||||
Acts as a function decorator, context manager or start/end manager and
|
||||
override the template loaders with the test loader. It could be used in the
|
||||
following ways:
|
||||
|
||||
@override_with_test_loader(templates_dict, use_cached_loader=True)
|
||||
def test_function(self):
|
||||
...
|
||||
|
||||
with override_with_test_loader(templates_dict) as test_loader:
|
||||
...
|
||||
|
||||
test_loader = override_with_test_loader.override(templates_dict)
|
||||
...
|
||||
override_with_test_loader.restore()
|
||||
"""
|
||||
|
||||
def __init__(self, templates_dict, use_cached_loader=False):
|
||||
self.loader = self._get_loader(templates_dict, use_cached_loader)
|
||||
super(override_with_test_loader, self).__init__(self.loader)
|
||||
|
||||
def __enter__(self):
|
||||
return super(override_with_test_loader, self).__enter__()[0]
|
||||
|
||||
@classmethod
|
||||
def override(cls, templates_dict, use_cached_loader=False):
|
||||
loader = cls._get_loader(templates_dict, use_cached_loader)
|
||||
return super(override_with_test_loader, cls).override(loader)[0]
|
||||
|
||||
@classmethod
|
||||
def _get_loader(cls, templates_dict, use_cached_loader=False):
|
||||
if use_cached_loader:
|
||||
template_loader = cached.Loader(('test_template_loader',))
|
||||
template_loader._cached_loaders = (test_template_loader,)
|
||||
else:
|
||||
template_loader = test_template_loader
|
||||
|
||||
setattr(loader, RESTORE_LOADERS_ATTR, loader.template_source_loaders)
|
||||
loader.template_source_loaders = (template_loader,)
|
||||
return template_loader
|
||||
|
||||
|
||||
def restore_template_loaders():
|
||||
"""
|
||||
Restores the original template loaders after
|
||||
:meth:`setup_test_template_loader` has been run.
|
||||
"""
|
||||
loader.template_source_loaders = getattr(loader, RESTORE_LOADERS_ATTR)
|
||||
delattr(loader, RESTORE_LOADERS_ATTR)
|
||||
loader = cached.Loader(('TestTemplateLoader',))
|
||||
loader._cached_loaders = TestTemplateLoader(templates_dict)
|
||||
return TestTemplateLoader(templates_dict)
|
||||
|
||||
|
||||
class override_settings(object):
|
||||
|
|
|
@ -15,8 +15,8 @@ from django.template import (base as template_base, loader, Context,
|
|||
RequestContext, Template, TemplateSyntaxError)
|
||||
from django.template.loaders import app_directories, filesystem, cached
|
||||
from django.test import RequestFactory, TestCase
|
||||
from django.test.utils import (setup_test_template_loader,
|
||||
restore_template_loaders, override_settings, extend_sys_path)
|
||||
from django.test.utils import (override_settings, override_template_loaders,
|
||||
override_with_test_loader, extend_sys_path)
|
||||
from django.utils.deprecation import RemovedInDjango19Warning, RemovedInDjango20Warning
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.formats import date_format
|
||||
|
@ -208,15 +208,11 @@ class TemplateLoaderTests(TestCase):
|
|||
test_template_sources('/DIR1/index.HTML', template_dirs,
|
||||
['/DIR1/index.HTML'])
|
||||
|
||||
@override_template_loaders(filesystem.Loader())
|
||||
# Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
|
||||
# the compiled templates.
|
||||
@override_settings(TEMPLATE_DEBUG=True)
|
||||
def test_loader_debug_origin(self):
|
||||
old_loaders = loader.template_source_loaders
|
||||
|
||||
try:
|
||||
loader.template_source_loaders = (filesystem.Loader(),)
|
||||
|
||||
# We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
|
||||
# point to a directory containing a login.html file. Also that
|
||||
# the file system and app directories loaders both inherit the
|
||||
|
@ -242,8 +238,6 @@ class TemplateLoaderTests(TestCase):
|
|||
template_name = template.nodelist[0].source[0].name
|
||||
self.assertTrue(template_name.endswith(load_name),
|
||||
'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
|
||||
finally:
|
||||
loader.template_source_loaders = old_loaders
|
||||
|
||||
def test_loader_origin(self):
|
||||
with self.settings(TEMPLATE_DEBUG=True):
|
||||
|
@ -262,19 +256,15 @@ class TemplateLoaderTests(TestCase):
|
|||
# TEMPLATE_DEBUG must be true, otherwise the exception raised
|
||||
# during {% include %} processing will be suppressed.
|
||||
@override_settings(TEMPLATE_DEBUG=True)
|
||||
# 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_template_loaders(app_directories.Loader())
|
||||
def test_include_missing_template(self):
|
||||
"""
|
||||
Tests that the correct template is identified as not existing
|
||||
when {% include %} specifies a template that does not exist.
|
||||
"""
|
||||
old_loaders = loader.template_source_loaders
|
||||
|
||||
try:
|
||||
# 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.
|
||||
loader.template_source_loaders = (app_directories.Loader(),)
|
||||
|
||||
load_name = 'test_include_error.html'
|
||||
r = None
|
||||
try:
|
||||
|
@ -283,12 +273,14 @@ class TemplateLoaderTests(TestCase):
|
|||
except template.TemplateDoesNotExist as e:
|
||||
self.assertEqual(e.args[0], 'missing.html')
|
||||
self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
|
||||
finally:
|
||||
loader.template_source_loaders = old_loaders
|
||||
|
||||
# TEMPLATE_DEBUG must be true, otherwise the exception raised
|
||||
# during {% include %} processing will be suppressed.
|
||||
@override_settings(TEMPLATE_DEBUG=True)
|
||||
# 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_template_loaders(app_directories.Loader())
|
||||
def test_extends_include_missing_baseloader(self):
|
||||
"""
|
||||
Tests that the correct template is identified as not existing
|
||||
|
@ -296,14 +288,6 @@ class TemplateLoaderTests(TestCase):
|
|||
that template has an {% include %} of something that does not
|
||||
exist. See #12787.
|
||||
"""
|
||||
old_loaders = loader.template_source_loaders
|
||||
|
||||
try:
|
||||
# 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.
|
||||
loader.template_source_loaders = (app_directories.Loader(),)
|
||||
|
||||
load_name = 'test_extends_error.html'
|
||||
tmpl = loader.get_template(load_name)
|
||||
r = None
|
||||
|
@ -312,8 +296,6 @@ class TemplateLoaderTests(TestCase):
|
|||
except template.TemplateDoesNotExist as e:
|
||||
self.assertEqual(e.args[0], 'missing.html')
|
||||
self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
|
||||
finally:
|
||||
loader.template_source_loaders = old_loaders
|
||||
|
||||
@override_settings(TEMPLATE_DEBUG=True)
|
||||
def test_extends_include_missing_cachedloader(self):
|
||||
|
@ -321,14 +303,9 @@ class TemplateLoaderTests(TestCase):
|
|||
Same as test_extends_include_missing_baseloader, only tests
|
||||
behavior of the cached loader instead of BaseLoader.
|
||||
"""
|
||||
|
||||
old_loaders = loader.template_source_loaders
|
||||
|
||||
try:
|
||||
cache_loader = cached.Loader(('',))
|
||||
cache_loader._cached_loaders = (app_directories.Loader(),)
|
||||
loader.template_source_loaders = (cache_loader,)
|
||||
|
||||
with override_template_loaders(cache_loader,):
|
||||
load_name = 'test_extends_error.html'
|
||||
tmpl = loader.get_template(load_name)
|
||||
r = None
|
||||
|
@ -346,8 +323,6 @@ class TemplateLoaderTests(TestCase):
|
|||
except template.TemplateDoesNotExist as e:
|
||||
self.assertEqual(e.args[0], 'missing.html')
|
||||
self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
|
||||
finally:
|
||||
loader.template_source_loaders = old_loaders
|
||||
|
||||
def test_include_template_argument(self):
|
||||
"""
|
||||
|
@ -544,11 +519,8 @@ class TemplateTests(TestCase):
|
|||
|
||||
template_tests.update(filter_tests)
|
||||
|
||||
cache_loader = setup_test_template_loader(
|
||||
dict((name, t[0]) for name, t in six.iteritems(template_tests)),
|
||||
use_cached_loader=True,
|
||||
)
|
||||
|
||||
templates = dict((name, t[0]) for name, t in six.iteritems(template_tests))
|
||||
with override_with_test_loader(templates, use_cached_loader=True) as cache_loader:
|
||||
failures = []
|
||||
tests = sorted(template_tests.items())
|
||||
|
||||
|
@ -581,7 +553,6 @@ class TemplateTests(TestCase):
|
|||
template_debug_result = vals[2]
|
||||
|
||||
with translation.override(vals[1].get('LANGUAGE_CODE', 'en-us')):
|
||||
|
||||
for invalid_str, template_debug, result in [
|
||||
('', False, normal_string_result),
|
||||
(expected_invalid_str, False, invalid_string_result),
|
||||
|
@ -625,8 +596,6 @@ class TemplateTests(TestCase):
|
|||
expected_invalid_str = 'INVALID'
|
||||
template_base.invalid_var_format_string = False
|
||||
|
||||
restore_template_loaders()
|
||||
|
||||
self.assertEqual(failures, [], "Tests failed:\n%s\n%s" %
|
||||
('-' * 70, ("\n%s\n" % ('-' * 70)).join(failures)))
|
||||
|
||||
|
@ -1887,13 +1856,13 @@ class RequestContextTests(unittest.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
templates = {
|
||||
'child': Template('{{ var|default:"none" }}'),
|
||||
'child': '{{ var|default:"none" }}',
|
||||
}
|
||||
setup_test_template_loader(templates)
|
||||
override_with_test_loader.override(templates)
|
||||
self.fake_request = RequestFactory().get('/')
|
||||
|
||||
def tearDown(self):
|
||||
restore_template_loaders()
|
||||
override_with_test_loader.restore()
|
||||
|
||||
def test_include_only(self):
|
||||
"""
|
||||
|
|
|
@ -17,8 +17,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.template.base import TemplateDoesNotExist
|
||||
from django.test import TestCase, RequestFactory, override_settings
|
||||
from django.test.utils import (
|
||||
setup_test_template_loader, restore_template_loaders)
|
||||
from django.test.utils import override_with_test_loader
|
||||
from django.utils.encoding import force_text, force_bytes
|
||||
from django.utils import six
|
||||
from django.views.debug import ExceptionReporter
|
||||
|
@ -47,23 +46,16 @@ class DebugViewTests(TestCase):
|
|||
|
||||
def test_403(self):
|
||||
# Ensure no 403.html template exists to test the default case.
|
||||
setup_test_template_loader({})
|
||||
try:
|
||||
with override_with_test_loader({}):
|
||||
response = self.client.get('/raises403/')
|
||||
self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403)
|
||||
finally:
|
||||
restore_template_loaders()
|
||||
|
||||
def test_403_template(self):
|
||||
# Set up a test 403.html template.
|
||||
setup_test_template_loader(
|
||||
{'403.html': 'This is a test template for a 403 Forbidden error.'}
|
||||
)
|
||||
try:
|
||||
with override_with_test_loader({'403.html': 'This is a test template '
|
||||
'for a 403 Forbidden error.'}):
|
||||
response = self.client.get('/raises403/')
|
||||
self.assertContains(response, 'test template', status_code=403)
|
||||
finally:
|
||||
restore_template_loaders()
|
||||
|
||||
def test_404(self):
|
||||
response = self.client.get('/raises404/')
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.utils import (setup_test_template_loader,
|
||||
restore_template_loaders, override_settings)
|
||||
from django.test.utils import override_settings, override_with_test_loader
|
||||
|
||||
from ..models import UrlArticle
|
||||
|
||||
|
@ -41,17 +40,13 @@ class DefaultsTests(TestCase):
|
|||
Test that 404.html and 500.html templates are picked by their respective
|
||||
handler.
|
||||
"""
|
||||
setup_test_template_loader(
|
||||
{'404.html': 'This is a test template for a 404 error.',
|
||||
'500.html': 'This is a test template for a 500 error.'}
|
||||
)
|
||||
try:
|
||||
with override_with_test_loader({
|
||||
'404.html': 'This is a test template for a 404 error.',
|
||||
'500.html': 'This is a test template for a 500 error.'}):
|
||||
for code, url in ((404, '/non_existing_url/'), (500, '/server_error/')):
|
||||
response = self.client.get(url)
|
||||
self.assertContains(response, "test template for a %d error" % code,
|
||||
status_code=code)
|
||||
finally:
|
||||
restore_template_loaders()
|
||||
|
||||
def test_get_absolute_url_attributes(self):
|
||||
"A model can set attributes on the get_absolute_url method"
|
||||
|
|
Loading…
Reference in New Issue