Updated template tests to create their own engine.

This continues work to treat Django templates as a library.
This commit is contained in:
Preston Timmons 2015-04-11 19:41:45 -04:00
parent d84f01ff08
commit fb267a1d85
11 changed files with 153 additions and 171 deletions

View File

@ -1,5 +1,5 @@
from django.core.cache import cache from django.core.cache import cache
from django.template import Context, Template, TemplateSyntaxError from django.template import Context, Engine, TemplateSyntaxError
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from ..utils import setup from ..utils import setup
@ -119,8 +119,13 @@ class CacheTagTests(SimpleTestCase):
class CacheTests(SimpleTestCase): class CacheTests(SimpleTestCase):
@classmethod
def setUpClass(cls):
cls.engine = Engine()
super(CacheTests, cls).setUpClass()
def test_cache_regression_20130(self): def test_cache_regression_20130(self):
t = Template('{% load cache %}{% cache 1 regression_20130 %}foo{% endcache %}') t = self.engine.from_string('{% load cache %}{% cache 1 regression_20130 %}foo{% endcache %}')
cachenode = t.nodelist[1] cachenode = t.nodelist[1]
self.assertEqual(cachenode.fragment_name, 'regression_20130') self.assertEqual(cachenode.fragment_name, 'regression_20130')
@ -139,8 +144,8 @@ class CacheTests(SimpleTestCase):
When a cache called "template_fragments" is present, the cache tag When a cache called "template_fragments" is present, the cache tag
will use it in preference to 'default' will use it in preference to 'default'
""" """
t1 = Template('{% load cache %}{% cache 1 fragment %}foo{% endcache %}') t1 = self.engine.from_string('{% load cache %}{% cache 1 fragment %}foo{% endcache %}')
t2 = Template('{% load cache %}{% cache 1 fragment using="default" %}bar{% endcache %}') t2 = self.engine.from_string('{% load cache %}{% cache 1 fragment using="default" %}bar{% endcache %}')
ctx = Context() ctx = Context()
o1 = t1.render(ctx) o1 = t1.render(ctx)
@ -154,7 +159,7 @@ class CacheTests(SimpleTestCase):
When a cache that doesn't exist is specified, the cache tag will When a cache that doesn't exist is specified, the cache tag will
raise a TemplateSyntaxError raise a TemplateSyntaxError
'""" '"""
t = Template('{% load cache %}{% cache 1 backend using="unknown" %}bar{% endcache %}') t = self.engine.from_string('{% load cache %}{% cache 1 backend using="unknown" %}bar{% endcache %}')
ctx = Context() ctx = Context()
with self.assertRaises(TemplateSyntaxError): with self.assertRaises(TemplateSyntaxError):

View File

@ -1,4 +1,4 @@
from django.template import Context, Template from django.template import Context, Engine
from django.test import SimpleTestCase from django.test import SimpleTestCase
from ..utils import setup from ..utils import setup
@ -157,11 +157,19 @@ class IfChangedTagTests(SimpleTestCase):
class IfChangedTests(SimpleTestCase): class IfChangedTests(SimpleTestCase):
@classmethod
def setUpClass(cls):
cls.engine = Engine()
super(IfChangedTests, cls).setUpClass()
def test_ifchanged_concurrency(self): def test_ifchanged_concurrency(self):
""" """
#15849 -- ifchanged should be thread-safe. #15849 -- ifchanged should be thread-safe.
""" """
template = Template('[0{% for x in foo %},{% with var=get_value %}{% ifchanged %}{{ var }}{% endifchanged %}{% endwith %}{% endfor %}]') template = self.engine.from_string(
'[0{% for x in foo %},{% with var=get_value %}{% ifchanged %}'
'{{ var }}{% endifchanged %}{% endwith %}{% endfor %}]'
)
# Using generator to mimic concurrency. # Using generator to mimic concurrency.
# The generator is not passed to the 'for' loop, because it does a list(values) # The generator is not passed to the 'for' loop, because it does a list(values)
@ -184,6 +192,6 @@ class IfChangedTests(SimpleTestCase):
""" """
#19890. The content of ifchanged template tag was rendered twice. #19890. The content of ifchanged template tag was rendered twice.
""" """
template = Template('{% ifchanged %}{% cycle "1st time" "2nd time" %}{% endifchanged %}') template = self.engine.from_string('{% ifchanged %}{% cycle "1st time" "2nd time" %}{% endifchanged %}')
output = template.render(Context({})) output = template.render(Context({}))
self.assertEqual(output, '1st time') self.assertEqual(output, '1st time')

View File

@ -1,7 +1,7 @@
from django.template import ( from django.template import (
Context, Template, TemplateDoesNotExist, TemplateSyntaxError, engines, Context, Engine, TemplateDoesNotExist, TemplateSyntaxError,
) )
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase
from ..utils import setup from ..utils import setup
from .test_basic import basic_templates from .test_basic import basic_templates
@ -205,110 +205,69 @@ class IncludeTagTests(SimpleTestCase):
class IncludeTests(SimpleTestCase): class IncludeTests(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(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
# Enable debug, otherwise the exception raised during
# {% include %} processing will be suppressed.
'debug': True,
}
}])
def test_include_missing_template(self): def test_include_missing_template(self):
""" """
Tests that the correct template is identified as not existing Tests that the correct template is identified as not existing
when {% include %} specifies a template that does not exist. when {% include %} specifies a template that does not exist.
""" """
template = engines['django'].get_template('test_include_error.html') engine = Engine(app_dirs=True, debug=True)
template = engine.get_template('test_include_error.html')
with self.assertRaises(TemplateDoesNotExist) as e: with self.assertRaises(TemplateDoesNotExist) as e:
template.render() template.render(Context())
self.assertEqual(e.exception.args[0], 'missing.html') self.assertEqual(e.exception.args[0], 'missing.html')
# 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(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
# Enable debug, otherwise the exception raised during
# {% include %} processing will be suppressed.
'debug': True,
}
}])
def test_extends_include_missing_baseloader(self): def test_extends_include_missing_baseloader(self):
""" """
#12787 -- Tests that the correct template is identified as not existing #12787 -- Tests that the correct template is identified as not existing
when {% extends %} specifies a template that does exist, but that when {% extends %} specifies a template that does exist, but that
template has an {% include %} of something that does not exist. template has an {% include %} of something that does not exist.
""" """
template = engines['django'].get_template('test_extends_error.html') engine = Engine(app_dirs=True, debug=True)
template = engine.get_template('test_extends_error.html')
with self.assertRaises(TemplateDoesNotExist) as e: with self.assertRaises(TemplateDoesNotExist) as e:
template.render() template.render(Context())
self.assertEqual(e.exception.args[0], 'missing.html') self.assertEqual(e.exception.args[0], 'missing.html')
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'debug': True,
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.app_directories.Loader',
]),
],
},
}])
def test_extends_include_missing_cachedloader(self): def test_extends_include_missing_cachedloader(self):
""" """
Test the cache loader separately since it overrides load_template. Test the cache loader separately since it overrides load_template.
""" """
engine = Engine(debug=True, loaders=[
('django.template.loaders.cached.Loader', [
'django.template.loaders.app_directories.Loader',
]),
])
template = engines['django'].get_template('test_extends_error.html') template = engine.get_template('test_extends_error.html')
with self.assertRaises(TemplateDoesNotExist) as e: with self.assertRaises(TemplateDoesNotExist) as e:
template.render() template.render(Context())
self.assertEqual(e.exception.args[0], 'missing.html') self.assertEqual(e.exception.args[0], 'missing.html')
# Repeat to ensure it still works when loading from the cache # Repeat to ensure it still works when loading from the cache
template = engines['django'].get_template('test_extends_error.html') template = engine.get_template('test_extends_error.html')
with self.assertRaises(TemplateDoesNotExist) as e: with self.assertRaises(TemplateDoesNotExist) as e:
template.render() template.render(Context())
self.assertEqual(e.exception.args[0], 'missing.html') self.assertEqual(e.exception.args[0], 'missing.html')
def test_include_template_argument(self): def test_include_template_argument(self):
""" """
Support any render() supporting object Support any render() supporting object
""" """
engine = Engine()
ctx = Context({ ctx = Context({
'tmpl': Template('This worked!'), 'tmpl': engine.from_string('This worked!'),
}) })
outer_tmpl = Template('{% include tmpl %}') outer_tmpl = engine.from_string('{% include tmpl %}')
output = outer_tmpl.render(ctx) output = outer_tmpl.render(ctx)
self.assertEqual(output, 'This worked!') self.assertEqual(output, 'This worked!')
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'debug': True,
},
}])
def test_include_immediate_missing(self): def test_include_immediate_missing(self):
""" """
#16417 -- Include tags pointing to missing templates should not raise #16417 -- Include tags pointing to missing templates should not raise
an error at parsing time. an error at parsing time.
""" """
template = Template('{% include "this_does_not_exist.html" %}') Engine(debug=True).from_string('{% include "this_does_not_exist.html" %}')
self.assertIsInstance(template, Template)
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
'debug': True,
},
}])
def test_include_recursive(self): def test_include_recursive(self):
comments = [ comments = [
{ {
@ -322,9 +281,9 @@ class IncludeTests(SimpleTestCase):
] ]
} }
] ]
engine = Engine(app_dirs=True)
t = engines['django'].get_template('recursive_include.html') t = engine.get_template('recursive_include.html')
self.assertEqual( self.assertEqual(
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1", "Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
t.render({'comments': comments}).replace(' ', '').replace('\n', ' ').strip(), t.render(Context({'comments': comments})).replace(' ', '').replace('\n', ' ').strip(),
) )

View File

@ -1,9 +1,9 @@
import operator import operator
from django.template import Library from django.template import Engine, Library
from django.template.loader import get_template
from django.utils import six from django.utils import six
engine = Engine(app_dirs=True)
register = Library() register = Library()
@ -14,7 +14,7 @@ def inclusion_no_params():
inclusion_no_params.anything = "Expected inclusion_no_params __dict__" inclusion_no_params.anything = "Expected inclusion_no_params __dict__"
@register.inclusion_tag(get_template('inclusion.html')) @register.inclusion_tag(engine.get_template('inclusion.html'))
def inclusion_no_params_from_template(): def inclusion_no_params_from_template():
"""Expected inclusion_no_params_from_template __doc__""" """Expected inclusion_no_params_from_template __doc__"""
return {"result": "inclusion_no_params_from_template - Expected result"} return {"result": "inclusion_no_params_from_template - Expected result"}
@ -28,7 +28,7 @@ def inclusion_one_param(arg):
inclusion_one_param.anything = "Expected inclusion_one_param __dict__" inclusion_one_param.anything = "Expected inclusion_one_param __dict__"
@register.inclusion_tag(get_template('inclusion.html')) @register.inclusion_tag(engine.get_template('inclusion.html'))
def inclusion_one_param_from_template(arg): def inclusion_one_param_from_template(arg):
"""Expected inclusion_one_param_from_template __doc__""" """Expected inclusion_one_param_from_template __doc__"""
return {"result": "inclusion_one_param_from_template - Expected result: %s" % arg} return {"result": "inclusion_one_param_from_template - Expected result: %s" % arg}
@ -42,7 +42,7 @@ def inclusion_explicit_no_context(arg):
inclusion_explicit_no_context.anything = "Expected inclusion_explicit_no_context __dict__" inclusion_explicit_no_context.anything = "Expected inclusion_explicit_no_context __dict__"
@register.inclusion_tag(get_template('inclusion.html'), takes_context=False) @register.inclusion_tag(engine.get_template('inclusion.html'), takes_context=False)
def inclusion_explicit_no_context_from_template(arg): def inclusion_explicit_no_context_from_template(arg):
"""Expected inclusion_explicit_no_context_from_template __doc__""" """Expected inclusion_explicit_no_context_from_template __doc__"""
return {"result": "inclusion_explicit_no_context_from_template - Expected result: %s" % arg} return {"result": "inclusion_explicit_no_context_from_template - Expected result: %s" % arg}
@ -56,7 +56,7 @@ def inclusion_no_params_with_context(context):
inclusion_no_params_with_context.anything = "Expected inclusion_no_params_with_context __dict__" inclusion_no_params_with_context.anything = "Expected inclusion_no_params_with_context __dict__"
@register.inclusion_tag(get_template('inclusion.html'), takes_context=True) @register.inclusion_tag(engine.get_template('inclusion.html'), takes_context=True)
def inclusion_no_params_with_context_from_template(context): def inclusion_no_params_with_context_from_template(context):
"""Expected inclusion_no_params_with_context_from_template __doc__""" """Expected inclusion_no_params_with_context_from_template __doc__"""
return {"result": "inclusion_no_params_with_context_from_template - Expected result (context value: %s)" % context['value']} return {"result": "inclusion_no_params_with_context_from_template - Expected result (context value: %s)" % context['value']}
@ -70,7 +70,7 @@ def inclusion_params_and_context(context, arg):
inclusion_params_and_context.anything = "Expected inclusion_params_and_context __dict__" inclusion_params_and_context.anything = "Expected inclusion_params_and_context __dict__"
@register.inclusion_tag(get_template('inclusion.html'), takes_context=True) @register.inclusion_tag(engine.get_template('inclusion.html'), takes_context=True)
def inclusion_params_and_context_from_template(context, arg): def inclusion_params_and_context_from_template(context, arg):
"""Expected inclusion_params_and_context_from_template __doc__""" """Expected inclusion_params_and_context_from_template __doc__"""
return {"result": "inclusion_params_and_context_from_template - Expected result (context value: %s): %s" % (context['value'], arg)} return {"result": "inclusion_params_and_context_from_template - Expected result (context value: %s): %s" % (context['value'], arg)}
@ -84,7 +84,7 @@ def inclusion_two_params(one, two):
inclusion_two_params.anything = "Expected inclusion_two_params __dict__" inclusion_two_params.anything = "Expected inclusion_two_params __dict__"
@register.inclusion_tag(get_template('inclusion.html')) @register.inclusion_tag(engine.get_template('inclusion.html'))
def inclusion_two_params_from_template(one, two): def inclusion_two_params_from_template(one, two):
"""Expected inclusion_two_params_from_template __doc__""" """Expected inclusion_two_params_from_template __doc__"""
return {"result": "inclusion_two_params_from_template - Expected result: %s, %s" % (one, two)} return {"result": "inclusion_two_params_from_template - Expected result: %s, %s" % (one, two)}
@ -98,7 +98,7 @@ def inclusion_one_default(one, two='hi'):
inclusion_one_default.anything = "Expected inclusion_one_default __dict__" inclusion_one_default.anything = "Expected inclusion_one_default __dict__"
@register.inclusion_tag(get_template('inclusion.html')) @register.inclusion_tag(engine.get_template('inclusion.html'))
def inclusion_one_default_from_template(one, two='hi'): def inclusion_one_default_from_template(one, two='hi'):
"""Expected inclusion_one_default_from_template __doc__""" """Expected inclusion_one_default_from_template __doc__"""
return {"result": "inclusion_one_default_from_template - Expected result: %s, %s" % (one, two)} return {"result": "inclusion_one_default_from_template - Expected result: %s, %s" % (one, two)}
@ -112,7 +112,7 @@ def inclusion_unlimited_args(one, two='hi', *args):
inclusion_unlimited_args.anything = "Expected inclusion_unlimited_args __dict__" inclusion_unlimited_args.anything = "Expected inclusion_unlimited_args __dict__"
@register.inclusion_tag(get_template('inclusion.html')) @register.inclusion_tag(engine.get_template('inclusion.html'))
def inclusion_unlimited_args_from_template(one, two='hi', *args): def inclusion_unlimited_args_from_template(one, two='hi', *args):
"""Expected inclusion_unlimited_args_from_template __doc__""" """Expected inclusion_unlimited_args_from_template __doc__"""
return {"result": "inclusion_unlimited_args_from_template - Expected result: %s" % (', '.join(six.text_type(arg) for arg in [one, two] + list(args)))} return {"result": "inclusion_unlimited_args_from_template - Expected result: %s" % (', '.join(six.text_type(arg) for arg in [one, two] + list(args)))}
@ -126,7 +126,7 @@ def inclusion_only_unlimited_args(*args):
inclusion_only_unlimited_args.anything = "Expected inclusion_only_unlimited_args __dict__" inclusion_only_unlimited_args.anything = "Expected inclusion_only_unlimited_args __dict__"
@register.inclusion_tag(get_template('inclusion.html')) @register.inclusion_tag(engine.get_template('inclusion.html'))
def inclusion_only_unlimited_args_from_template(*args): def inclusion_only_unlimited_args_from_template(*args):
"""Expected inclusion_only_unlimited_args_from_template __doc__""" """Expected inclusion_only_unlimited_args_from_template __doc__"""
return {"result": "inclusion_only_unlimited_args_from_template - Expected result: %s" % (', '.join(six.text_type(arg) for arg in args))} return {"result": "inclusion_only_unlimited_args_from_template - Expected result: %s" % (', '.join(six.text_type(arg) for arg in args))}

View File

@ -2,11 +2,16 @@ from __future__ import unicode_literals
from unittest import TestCase from unittest import TestCase
from django import template from django.template import Context, Engine
class CallableVariablesTests(TestCase): class CallableVariablesTests(TestCase):
@classmethod
def setUpClass(cls):
cls.engine = Engine()
super(CallableVariablesTests, cls).setUpClass()
def test_callable(self): def test_callable(self):
class Doodad(object): class Doodad(object):
@ -19,12 +24,12 @@ class CallableVariablesTests(TestCase):
return {"the_value": self.value} return {"the_value": self.value}
my_doodad = Doodad(42) my_doodad = Doodad(42)
c = template.Context({"my_doodad": my_doodad}) c = Context({"my_doodad": my_doodad})
# We can't access ``my_doodad.value`` in the template, because # We can't access ``my_doodad.value`` in the template, because
# ``my_doodad.__call__`` will be invoked first, yielding a dictionary # ``my_doodad.__call__`` will be invoked first, yielding a dictionary
# without a key ``value``. # without a key ``value``.
t = template.Template('{{ my_doodad.value }}') t = self.engine.from_string('{{ my_doodad.value }}')
self.assertEqual(t.render(c), '') self.assertEqual(t.render(c), '')
# We can confirm that the doodad has been called # We can confirm that the doodad has been called
@ -32,7 +37,7 @@ class CallableVariablesTests(TestCase):
# But we can access keys on the dict that's returned # But we can access keys on the dict that's returned
# by ``__call__``, instead. # by ``__call__``, instead.
t = template.Template('{{ my_doodad.the_value }}') t = self.engine.from_string('{{ my_doodad.the_value }}')
self.assertEqual(t.render(c), '42') self.assertEqual(t.render(c), '42')
self.assertEqual(my_doodad.num_calls, 2) self.assertEqual(my_doodad.num_calls, 2)
@ -50,13 +55,13 @@ class CallableVariablesTests(TestCase):
return {"the_value": self.value} return {"the_value": self.value}
my_doodad = Doodad(42) my_doodad = Doodad(42)
c = template.Context({"my_doodad": my_doodad}) c = Context({"my_doodad": my_doodad})
# Since ``my_doodad.alters_data`` is True, the template system will not # Since ``my_doodad.alters_data`` is True, the template system will not
# try to call our doodad but will use string_if_invalid # try to call our doodad but will use string_if_invalid
t = template.Template('{{ my_doodad.value }}') t = self.engine.from_string('{{ my_doodad.value }}')
self.assertEqual(t.render(c), '') self.assertEqual(t.render(c), '')
t = template.Template('{{ my_doodad.the_value }}') t = self.engine.from_string('{{ my_doodad.the_value }}')
self.assertEqual(t.render(c), '') self.assertEqual(t.render(c), '')
# Double-check that the object was really never called during the # Double-check that the object was really never called during the
@ -77,15 +82,15 @@ class CallableVariablesTests(TestCase):
return {"the_value": self.value} return {"the_value": self.value}
my_doodad = Doodad(42) my_doodad = Doodad(42)
c = template.Context({"my_doodad": my_doodad}) c = Context({"my_doodad": my_doodad})
# Since ``my_doodad.do_not_call_in_templates`` is True, the template # Since ``my_doodad.do_not_call_in_templates`` is True, the template
# system will not try to call our doodad. We can access its attributes # system will not try to call our doodad. We can access its attributes
# as normal, and we don't have access to the dict that it returns when # as normal, and we don't have access to the dict that it returns when
# called. # called.
t = template.Template('{{ my_doodad.value }}') t = self.engine.from_string('{{ my_doodad.value }}')
self.assertEqual(t.render(c), '42') self.assertEqual(t.render(c), '42')
t = template.Template('{{ my_doodad.the_value }}') t = self.engine.from_string('{{ my_doodad.the_value }}')
self.assertEqual(t.render(c), '') self.assertEqual(t.render(c), '')
# Double-check that the object was really never called during the # Double-check that the object was really never called during the
@ -110,11 +115,11 @@ class CallableVariablesTests(TestCase):
return {"the_value": self.value} return {"the_value": self.value}
my_doodad = Doodad(42) my_doodad = Doodad(42)
c = template.Context({"my_doodad": my_doodad}) c = Context({"my_doodad": my_doodad})
t = template.Template('{{ my_doodad.value }}') t = self.engine.from_string('{{ my_doodad.value }}')
self.assertEqual(t.render(c), '42') self.assertEqual(t.render(c), '42')
t = template.Template('{{ my_doodad.the_value }}') t = self.engine.from_string('{{ my_doodad.the_value }}')
self.assertEqual(t.render(c), '') self.assertEqual(t.render(c), '')
# Double-check that the object was really never called during the # Double-check that the object was really never called during the

View File

@ -2,10 +2,10 @@
from django.http import HttpRequest from django.http import HttpRequest
from django.template import ( from django.template import (
Context, RequestContext, Template, Variable, VariableDoesNotExist, Context, Engine, RequestContext, Variable, VariableDoesNotExist,
) )
from django.template.context import RenderContext from django.template.context import RenderContext
from django.test import RequestFactory, SimpleTestCase, override_settings from django.test import RequestFactory, SimpleTestCase
class ContextTests(SimpleTestCase): class ContextTests(SimpleTestCase):
@ -131,25 +131,20 @@ class ContextTests(SimpleTestCase):
class RequestContextTests(SimpleTestCase): class RequestContextTests(SimpleTestCase):
@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): def test_include_only(self):
""" """
#15721 -- ``{% include %}`` and ``RequestContext`` should work #15721 -- ``{% include %}`` and ``RequestContext`` should work
together. together.
""" """
engine = Engine(loaders=[
('django.template.loaders.locmem.Loader', {
'child': '{{ var|default:"none" }}',
}),
])
request = RequestFactory().get('/') request = RequestFactory().get('/')
ctx = RequestContext(request, {'var': 'parent'}) ctx = RequestContext(request, {'var': 'parent'})
self.assertEqual(Template('{% include "child" %}').render(ctx), 'parent') self.assertEqual(engine.from_string('{% include "child" %}').render(ctx), 'parent')
self.assertEqual(Template('{% include "child" only %}').render(ctx), 'none') self.assertEqual(engine.from_string('{% include "child" only %}').render(ctx), 'none')
def test_stack_size(self): def test_stack_size(self):
""" """

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
import os import os
from django.template import Context, Engine, Template, TemplateSyntaxError from django.template import Context, Engine, TemplateSyntaxError
from django.template.base import Node from django.template.base import Node
from django.test import SimpleTestCase, ignore_warnings from django.test import SimpleTestCase, ignore_warnings
from django.test.utils import extend_sys_path from django.test.utils import extend_sys_path
@ -15,7 +15,7 @@ from .utils import ROOT
class CustomFilterTests(SimpleTestCase): class CustomFilterTests(SimpleTestCase):
def test_filter(self): def test_filter(self):
t = Template("{% load custom %}{{ string|trim:5 }}") t = Engine().from_string("{% load custom %}{{ string|trim:5 }}")
self.assertEqual( self.assertEqual(
t.render(Context({"string": "abcdefghijklmnopqrstuvwxyz"})), t.render(Context({"string": "abcdefghijklmnopqrstuvwxyz"})),
"abcde" "abcde"
@ -24,6 +24,11 @@ class CustomFilterTests(SimpleTestCase):
class TagTestCase(SimpleTestCase): class TagTestCase(SimpleTestCase):
@classmethod
def setUpClass(cls):
cls.engine = Engine(app_dirs=True)
super(TagTestCase, cls).setUpClass()
def verify_tag(self, tag, name): def verify_tag(self, tag, name):
self.assertEqual(tag.__name__, name) self.assertEqual(tag.__name__, name)
self.assertEqual(tag.__doc__, 'Expected %s __doc__' % name) self.assertEqual(tag.__doc__, 'Expected %s __doc__' % name)
@ -62,11 +67,11 @@ class SimpleTagTests(TagTestCase):
] ]
for entry in templates: for entry in templates:
t = Template(entry[0]) t = self.engine.from_string(entry[0])
self.assertEqual(t.render(c), entry[1]) self.assertEqual(t.render(c), entry[1])
for entry in templates: for entry in templates:
t = Template("%s as var %%}Result: {{ var }}" % entry[0][0:-2]) t = self.engine.from_string("%s as var %%}Result: {{ var }}" % entry[0][0:-2])
self.assertEqual(t.render(c), "Result: %s" % entry[1]) self.assertEqual(t.render(c), "Result: %s" % entry[1])
def test_simple_tag_errors(self): def test_simple_tag_errors(self):
@ -85,11 +90,11 @@ class SimpleTagTests(TagTestCase):
for entry in errors: for entry in errors:
with self.assertRaisesMessage(TemplateSyntaxError, entry[0]): with self.assertRaisesMessage(TemplateSyntaxError, entry[0]):
Template(entry[1]) self.engine.from_string(entry[1])
for entry in errors: for entry in errors:
with self.assertRaisesMessage(TemplateSyntaxError, entry[0]): with self.assertRaisesMessage(TemplateSyntaxError, entry[0]):
Template("%s as var %%}" % entry[1][0:-2]) self.engine.from_string("%s as var %%}" % entry[1][0:-2])
def test_simple_tag_registration(self): def test_simple_tag_registration(self):
# Test that the decorators preserve the decorated function's docstring, name and attributes. # Test that the decorators preserve the decorated function's docstring, name and attributes.
@ -108,7 +113,7 @@ class SimpleTagTests(TagTestCase):
"takes_context=True so it must have a first argument of 'context'" "takes_context=True so it must have a first argument of 'context'"
) )
with self.assertRaisesMessage(TemplateSyntaxError, msg): with self.assertRaisesMessage(TemplateSyntaxError, msg):
Template('{% load custom %}{% simple_tag_without_context_parameter 123 %}') self.engine.from_string('{% load custom %}{% simple_tag_without_context_parameter 123 %}')
class InclusionTagTests(TagTestCase): class InclusionTagTests(TagTestCase):
@ -147,7 +152,7 @@ class InclusionTagTests(TagTestCase):
] ]
for entry in templates: for entry in templates:
t = Template(entry[0]) t = self.engine.from_string(entry[0])
self.assertEqual(t.render(c), entry[1]) self.assertEqual(t.render(c), entry[1])
def test_inclusion_tag_errors(self): def test_inclusion_tag_errors(self):
@ -173,7 +178,7 @@ class InclusionTagTests(TagTestCase):
for entry in errors: for entry in errors:
with self.assertRaisesMessage(TemplateSyntaxError, entry[0]): with self.assertRaisesMessage(TemplateSyntaxError, entry[0]):
Template(entry[1]) self.engine.from_string(entry[1])
def test_include_tag_missing_context(self): def test_include_tag_missing_context(self):
# The 'context' parameter must be present when takes_context is True # The 'context' parameter must be present when takes_context is True
@ -182,7 +187,7 @@ class InclusionTagTests(TagTestCase):
"takes_context=True so it must have a first argument of 'context'" "takes_context=True so it must have a first argument of 'context'"
) )
with self.assertRaisesMessage(TemplateSyntaxError, msg): with self.assertRaisesMessage(TemplateSyntaxError, msg):
Template('{% load inclusion %}{% inclusion_tag_without_context_parameter 123 %}') self.engine.from_string('{% load inclusion %}{% inclusion_tag_without_context_parameter 123 %}')
def test_inclusion_tags_from_template(self): def test_inclusion_tags_from_template(self):
c = Context({'value': 42}) c = Context({'value': 42})
@ -215,7 +220,7 @@ class InclusionTagTests(TagTestCase):
] ]
for entry in templates: for entry in templates:
t = Template(entry[0]) t = self.engine.from_string(entry[0])
self.assertEqual(t.render(c), entry[1]) self.assertEqual(t.render(c), entry[1])
def test_inclusion_tag_registration(self): def test_inclusion_tag_registration(self):
@ -241,7 +246,7 @@ class InclusionTagTests(TagTestCase):
Context of the included/rendered template as well. Context of the included/rendered template as well.
""" """
c = Context({}) c = Context({})
t = Template('{% load inclusion %}{% inclusion_tag_current_app %}') t = self.engine.from_string('{% load inclusion %}{% inclusion_tag_current_app %}')
self.assertEqual(t.render(c).strip(), 'None') self.assertEqual(t.render(c).strip(), 'None')
# That part produces the deprecation warning # That part produces the deprecation warning
@ -254,7 +259,7 @@ class InclusionTagTests(TagTestCase):
Context of the included/rendered template as well. Context of the included/rendered template as well.
""" """
c = Context({}) c = Context({})
t = Template('{% load inclusion %}{% inclusion_tag_use_l10n %}') t = self.engine.from_string('{% load inclusion %}{% inclusion_tag_use_l10n %}')
self.assertEqual(t.render(c).strip(), 'None') self.assertEqual(t.render(c).strip(), 'None')
c.use_l10n = True c.use_l10n = True
@ -286,7 +291,7 @@ class AssignmentTagTests(TagTestCase):
def test_assignment_tags(self): def test_assignment_tags(self):
c = Context({'value': 42}) c = Context({'value': 42})
t = Template('{% load custom %}{% assignment_no_params as var %}The result is: {{ var }}') t = self.engine.from_string('{% load custom %}{% assignment_no_params as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_no_params - Expected result') self.assertEqual(t.render(c), 'The result is: assignment_no_params - Expected result')
def test_assignment_tag_registration(self): def test_assignment_tag_registration(self):
@ -300,18 +305,21 @@ class AssignmentTagTests(TagTestCase):
"takes_context=True so it must have a first argument of 'context'" "takes_context=True so it must have a first argument of 'context'"
) )
with self.assertRaisesMessage(TemplateSyntaxError, msg): with self.assertRaisesMessage(TemplateSyntaxError, msg):
Template('{% load custom %}{% assignment_tag_without_context_parameter 123 as var %}') self.engine.from_string('{% load custom %}{% assignment_tag_without_context_parameter 123 as var %}')
class TemplateTagLoadingTests(SimpleTestCase): class TemplateTagLoadingTests(SimpleTestCase):
def setUp(self): @classmethod
self.egg_dir = os.path.join(ROOT, 'eggs') def setUpClass(cls):
cls.egg_dir = os.path.join(ROOT, 'eggs')
cls.engine = Engine()
super(TemplateTagLoadingTests, cls).setUpClass()
def test_load_error(self): def test_load_error(self):
ttext = "{% load broken_tag %}" ttext = "{% load broken_tag %}"
with self.assertRaises(TemplateSyntaxError) as e: with self.assertRaises(TemplateSyntaxError) as e:
Template(ttext) self.engine.from_string(ttext)
self.assertIn('ImportError', e.exception.args[0]) self.assertIn('ImportError', e.exception.args[0])
self.assertIn('Xtemplate', e.exception.args[0]) self.assertIn('Xtemplate', e.exception.args[0])
@ -322,10 +330,10 @@ class TemplateTagLoadingTests(SimpleTestCase):
with extend_sys_path(egg_name): with extend_sys_path(egg_name):
with self.assertRaises(TemplateSyntaxError): with self.assertRaises(TemplateSyntaxError):
with self.settings(INSTALLED_APPS=['tagsegg']): with self.settings(INSTALLED_APPS=['tagsegg']):
Template(ttext) self.engine.from_string(ttext)
try: try:
with self.settings(INSTALLED_APPS=['tagsegg']): with self.settings(INSTALLED_APPS=['tagsegg']):
Template(ttext) self.engine.from_string(ttext)
except TemplateSyntaxError as e: except TemplateSyntaxError as e:
self.assertIn('ImportError', e.args[0]) self.assertIn('ImportError', e.args[0])
self.assertIn('Xtemplate', e.args[0]) self.assertIn('Xtemplate', e.args[0])
@ -335,4 +343,4 @@ class TemplateTagLoadingTests(SimpleTestCase):
egg_name = '%s/tagsegg.egg' % self.egg_dir egg_name = '%s/tagsegg.egg' % self.egg_dir
with extend_sys_path(egg_name): with extend_sys_path(egg_name):
with self.settings(INSTALLED_APPS=['tagsegg']): with self.settings(INSTALLED_APPS=['tagsegg']):
Template(ttext) self.engine.from_string(ttext)

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
import logging import logging
from django.template import Template, Variable, VariableDoesNotExist from django.template import Engine, Variable, VariableDoesNotExist
from django.test import SimpleTestCase from django.test import SimpleTestCase
@ -38,7 +38,7 @@ class VariableResolveLoggingTests(SimpleTestCase):
@property @property
def template(self): def template(self):
return Template('') return Engine().from_string('')
@property @property
def article(self): def article(self):

View File

@ -1,29 +1,33 @@
from unittest import TestCase from unittest import TestCase
from django.template import Context, Template from django.template import Context, Engine
from django.template.base import VariableNode from django.template.base import VariableNode
from django.test import override_settings
class NodelistTest(TestCase): class NodelistTest(TestCase):
@classmethod
def setUpClass(cls):
cls.engine = Engine()
super(NodelistTest, cls).setUpClass()
def test_for(self): def test_for(self):
template = Template('{% for i in 1 %}{{ a }}{% endfor %}') template = self.engine.from_string('{% for i in 1 %}{{ a }}{% endfor %}')
vars = template.nodelist.get_nodes_by_type(VariableNode) vars = template.nodelist.get_nodes_by_type(VariableNode)
self.assertEqual(len(vars), 1) self.assertEqual(len(vars), 1)
def test_if(self): def test_if(self):
template = Template('{% if x %}{{ a }}{% endif %}') template = self.engine.from_string('{% if x %}{{ a }}{% endif %}')
vars = template.nodelist.get_nodes_by_type(VariableNode) vars = template.nodelist.get_nodes_by_type(VariableNode)
self.assertEqual(len(vars), 1) self.assertEqual(len(vars), 1)
def test_ifequal(self): def test_ifequal(self):
template = Template('{% ifequal x y %}{{ a }}{% endifequal %}') template = self.engine.from_string('{% ifequal x y %}{{ a }}{% endifequal %}')
vars = template.nodelist.get_nodes_by_type(VariableNode) vars = template.nodelist.get_nodes_by_type(VariableNode)
self.assertEqual(len(vars), 1) self.assertEqual(len(vars), 1)
def test_ifchanged(self): def test_ifchanged(self):
template = Template('{% ifchanged x %}{{ a }}{% endifchanged %}') template = self.engine.from_string('{% ifchanged x %}{{ a }}{% endifchanged %}')
vars = template.nodelist.get_nodes_by_type(VariableNode) vars = template.nodelist.get_nodes_by_type(VariableNode)
self.assertEqual(len(vars), 1) self.assertEqual(len(vars), 1)
@ -33,7 +37,6 @@ class ErrorIndexTest(TestCase):
Checks whether index of error is calculated correctly in Checks whether index of error is calculated correctly in
template debugger in for loops. Refs ticket #5831 template debugger in for loops. Refs ticket #5831
""" """
@override_settings(DEBUG=True)
def test_correct_exception_index(self): def test_correct_exception_index(self):
tests = [ tests = [
('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (38, 56)), ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (38, 56)),
@ -46,8 +49,9 @@ class ErrorIndexTest(TestCase):
'range': range(5), 'range': range(5),
'five': 5, 'five': 5,
}) })
engine = Engine(debug=True)
for source, expected_error_source_index in tests: for source, expected_error_source_index in tests:
template = Template(source) template = engine.from_string(source)
try: try:
template.render(context) template.render(context)
except (RuntimeError, TypeError) as e: except (RuntimeError, TypeError) as e:

View File

@ -3,7 +3,7 @@ from __future__ import unicode_literals
from unittest import TestCase from unittest import TestCase
from django.template import Context, Template from django.template import Context, Engine
from django.template.base import TemplateEncodingError from django.template.base import TemplateEncodingError
from django.utils import six from django.utils import six
from django.utils.safestring import SafeData from django.utils.safestring import SafeData
@ -12,13 +12,14 @@ from django.utils.safestring import SafeData
class UnicodeTests(TestCase): class UnicodeTests(TestCase):
def test_template(self): def test_template(self):
# Templates can be created from unicode strings. # Templates can be created from unicode strings.
t1 = Template('ŠĐĆŽćžšđ {{ var }}') engine = Engine()
t1 = engine.from_string('ŠĐĆŽćžšđ {{ var }}')
# Templates can also be created from bytestrings. These are assumed to # Templates can also be created from bytestrings. These are assumed to
# be encoded using UTF-8. # be encoded using UTF-8.
s = b'\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91 {{ var }}' s = b'\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91 {{ var }}'
t2 = Template(s) t2 = engine.from_string(s)
s = b'\x80\xc5\xc0' with self.assertRaises(TemplateEncodingError):
self.assertRaises(TemplateEncodingError, Template, s) engine.from_string(b'\x80\xc5\xc0')
# Contexts can be constructed from unicode or UTF-8 bytestrings. # Contexts can be constructed from unicode or UTF-8 bytestrings.
Context({b"var": b"foo"}) Context({b"var": b"foo"})

View File

@ -5,37 +5,33 @@ import sys
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.core import urlresolvers from django.core import urlresolvers
from django.template import ( from django.template import Context, Engine, TemplateSyntaxError
Context, Engine, Template, TemplateSyntaxError, engines, loader,
)
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
class TemplateTests(SimpleTestCase): class TemplateTests(SimpleTestCase):
@override_settings(DEBUG=True)
def test_string_origin(self): def test_string_origin(self):
template = Template('string template') template = Engine().from_string('string template')
self.assertEqual(template.origin.source, 'string template') self.assertEqual(template.origin.source, 'string template')
@override_settings(SETTINGS_MODULE=None, DEBUG=True) @override_settings(SETTINGS_MODULE=None)
def test_url_reverse_no_settings_module(self): def test_url_reverse_no_settings_module(self):
# Regression test for #9005 """
t = Template('{% url will_not_match %}') #9005 -- url tag shouldn't require settings.SETTINGS_MODULE to
be set.
"""
t = Engine(debug=True).from_string('{% url will_not_match %}')
c = Context() c = Context()
with self.assertRaises(urlresolvers.NoReverseMatch): with self.assertRaises(urlresolvers.NoReverseMatch):
t.render(c) t.render(c)
@override_settings(
TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {'string_if_invalid': '%s is invalid'},
}],
SETTINGS_MODULE='also_something',
)
def test_url_reverse_view_name(self): def test_url_reverse_view_name(self):
# Regression test for #19827 """
t = Template('{% url will_not_match %}') #19827 -- url tag should keep original strack trace when reraising
exception.
"""
t = Engine().from_string('{% url will_not_match %}')
c = Context() c = Context()
try: try:
t.render(c) t.render(c)
@ -107,9 +103,10 @@ class TemplateTests(SimpleTestCase):
""" """
#18169 -- NoReverseMatch should not be silence in block.super. #18169 -- NoReverseMatch should not be silence in block.super.
""" """
t = loader.get_template('included_content.html') engine = Engine(app_dirs=True)
t = engine.get_template('included_content.html')
with self.assertRaises(urlresolvers.NoReverseMatch): with self.assertRaises(urlresolvers.NoReverseMatch):
t.render() t.render(Context())
def test_debug_tag_non_ascii(self): def test_debug_tag_non_ascii(self):
""" """
@ -117,7 +114,7 @@ class TemplateTests(SimpleTestCase):
""" """
Group.objects.create(name="清風") Group.objects.create(name="清風")
c1 = Context({"objs": Group.objects.all()}) c1 = Context({"objs": Group.objects.all()})
t1 = Template('{% debug %}') t1 = Engine().from_string('{% debug %}')
self.assertIn("清風", t1.render(c1)) self.assertIn("清風", t1.render(c1))
def test_extends_generic_template(self): def test_extends_generic_template(self):
@ -125,8 +122,8 @@ class TemplateTests(SimpleTestCase):
#24338 -- Allow extending django.template.backends.django.Template #24338 -- Allow extending django.template.backends.django.Template
objects. objects.
""" """
parent = engines['django'].from_string( engine = Engine()
'{% block content %}parent{% endblock %}') parent = engine.from_string('{% block content %}parent{% endblock %}')
child = engines['django'].from_string( child = engine.from_string(
'{% extends parent %}{% block content %}child{% endblock %}') '{% extends parent %}{% block content %}child{% endblock %}')
self.assertEqual(child.render({'parent': parent}), 'child') self.assertEqual(child.render(Context({'parent': parent})), 'child')