Fixed #18651 -- Enabled optional assignments for simple_tag().

This commit is contained in:
Preston Timmons 2015-01-16 17:34:32 -06:00 committed by Tim Graham
parent 8adc59038c
commit cd4282816d
6 changed files with 130 additions and 319 deletions

View File

@ -61,7 +61,8 @@ from django.apps import apps
from django.template.context import (BaseContext, Context, RequestContext, # NOQA: imported for backwards compatibility from django.template.context import (BaseContext, Context, RequestContext, # NOQA: imported for backwards compatibility
ContextPopException) ContextPopException)
from django.utils import lru_cache from django.utils import lru_cache
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import (RemovedInDjango20Warning,
RemovedInDjango21Warning)
from django.utils.itercompat import is_iterable from django.utils.itercompat import is_iterable
from django.utils.text import (smart_split, unescape_string_literal, from django.utils.text import (smart_split, unescape_string_literal,
get_text_list) get_text_list)
@ -1021,9 +1022,9 @@ def token_kwargs(bits, parser, support_legacy=False):
def parse_bits(parser, bits, params, varargs, varkw, defaults, def parse_bits(parser, bits, params, varargs, varkw, defaults,
takes_context, name): takes_context, name):
""" """
Parses bits for template tag helpers (simple_tag, include_tag and Parses bits for template tag helpers simple_tag and inclusion_tag, in
assignment_tag), in particular by detecting syntax errors and by particular by detecting syntax errors and by extracting positional and
extracting positional and keyword arguments. keyword arguments.
""" """
if takes_context: if takes_context:
if params[0] == 'context': if params[0] == 'context':
@ -1099,9 +1100,9 @@ def generic_tag_compiler(parser, token, params, varargs, varkw, defaults,
class TagHelperNode(Node): class TagHelperNode(Node):
""" """
Base class for tag helper nodes such as SimpleNode, InclusionNode and Base class for tag helper nodes such as SimpleNode and InclusionNode.
AssignmentNode. Manages the positional and keyword arguments to be passed Manages the positional and keyword arguments to be passed to the decorated
to the decorated function. function.
""" """
def __init__(self, takes_context, args, kwargs): def __init__(self, takes_context, args, kwargs):
@ -1191,17 +1192,31 @@ class Library(object):
params, varargs, varkw, defaults = getargspec(func) params, varargs, varkw, defaults = getargspec(func)
class SimpleNode(TagHelperNode): class SimpleNode(TagHelperNode):
def __init__(self, takes_context, args, kwargs, target_var):
super(SimpleNode, self).__init__(takes_context, args, kwargs)
self.target_var = target_var
def render(self, context): def render(self, context):
resolved_args, resolved_kwargs = self.get_resolved_arguments(context) resolved_args, resolved_kwargs = self.get_resolved_arguments(context)
return func(*resolved_args, **resolved_kwargs) output = func(*resolved_args, **resolved_kwargs)
if self.target_var is not None:
context[self.target_var] = output
return ''
return output
function_name = (name or function_name = (name or
getattr(func, '_decorated_function', func).__name__) getattr(func, '_decorated_function', func).__name__)
compile_func = partial(generic_tag_compiler,
params=params, varargs=varargs, varkw=varkw, def compile_func(parser, token):
defaults=defaults, name=function_name, bits = token.split_contents()[1:]
takes_context=takes_context, node_class=SimpleNode) target_var = None
if len(bits) >= 2 and bits[-2] == 'as':
target_var = bits[-1]
bits = bits[:-2]
args, kwargs = parse_bits(parser, bits, params,
varargs, varkw, defaults, takes_context, function_name)
return SimpleNode(takes_context, args, kwargs, target_var)
compile_func.__doc__ = func.__doc__ compile_func.__doc__ = func.__doc__
self.tag(function_name, compile_func) self.tag(function_name, compile_func)
return func return func
@ -1216,46 +1231,12 @@ class Library(object):
raise TemplateSyntaxError("Invalid arguments provided to simple_tag") raise TemplateSyntaxError("Invalid arguments provided to simple_tag")
def assignment_tag(self, func=None, takes_context=None, name=None): def assignment_tag(self, func=None, takes_context=None, name=None):
def dec(func): warnings.warn(
params, varargs, varkw, defaults = getargspec(func) "assignment_tag() is deprecated. Use simple_tag() instead",
RemovedInDjango21Warning,
class AssignmentNode(TagHelperNode): stacklevel=2,
def __init__(self, takes_context, args, kwargs, target_var): )
super(AssignmentNode, self).__init__(takes_context, args, kwargs) return self.simple_tag(func, takes_context, name)
self.target_var = target_var
def render(self, context):
resolved_args, resolved_kwargs = self.get_resolved_arguments(context)
context[self.target_var] = func(*resolved_args, **resolved_kwargs)
return ''
function_name = (name or
getattr(func, '_decorated_function', func).__name__)
def compile_func(parser, token):
bits = token.split_contents()[1:]
if len(bits) < 2 or bits[-2] != 'as':
raise TemplateSyntaxError(
"'%s' tag takes at least 2 arguments and the "
"second last argument must be 'as'" % function_name)
target_var = bits[-1]
bits = bits[:-2]
args, kwargs = parse_bits(parser, bits, params,
varargs, varkw, defaults, takes_context, function_name)
return AssignmentNode(takes_context, args, kwargs, target_var)
compile_func.__doc__ = func.__doc__
self.tag(function_name, compile_func)
return func
if func is None:
# @register.assignment_tag(...)
return dec
elif callable(func):
# @register.assignment_tag
return dec(func)
else:
raise TemplateSyntaxError("Invalid arguments provided to assignment_tag")
def inclusion_tag(self, file_name, takes_context=False, name=None): def inclusion_tag(self, file_name, takes_context=False, name=None):
def dec(func): def dec(func):

View File

@ -388,7 +388,7 @@ Simple tags
.. method:: django.template.Library.simple_tag() .. method:: django.template.Library.simple_tag()
Many template tags take a number of arguments -- strings or template variables Many template tags take a number of arguments -- strings or template variables
-- and return a string after doing some processing based solely on -- and return a result after doing some processing based solely on
the input arguments and some external information. For example, a the input arguments and some external information. For example, a
``current_time`` tag might accept a format string and return the time as a ``current_time`` tag might accept a format string and return the time as a
string formatted accordingly. string formatted accordingly.
@ -459,6 +459,18 @@ positional arguments. For example:
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %} {% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
.. versionadded:: 1.9
It's possible to store the tag results in a template variable rather than
directly outputting it. This is done by using the ``as`` argument followed by
the variable name. Doing so enables you to output the content yourself where
you see fit:
.. code-block:: html+django
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>
.. _howto-custom-template-tags-inclusion-tags: .. _howto-custom-template-tags-inclusion-tags:
Inclusion tags Inclusion tags
@ -602,11 +614,15 @@ Assignment tags
.. method:: django.template.Library.assignment_tag() .. method:: django.template.Library.assignment_tag()
.. deprecated:: 1.9
``simple_tag`` can now store results in a template variable and should
be used instead.
To ease the creation of tags setting a variable in the context, Django provides To ease the creation of tags setting a variable in the context, Django provides
a helper function, ``assignment_tag``. This function works the same way as a helper function, ``assignment_tag``. This function works the same way as
:ref:`simple_tag<howto-custom-template-tags-simple-tags>`, except that it :meth:`~django.template.Library.simple_tag` except that it stores the tag's
stores the tag's result in a specified context variable instead of directly result in a specified context variable instead of directly outputting it.
outputting it.
Our earlier ``current_time`` function could thus be written like this:: Our earlier ``current_time`` function could thus be written like this::
@ -622,38 +638,6 @@ followed by the variable name, and output it yourself where you see fit:
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %} {% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p> <p>The time is {{ the_time }}.</p>
If your template tag needs to access the current context, you can use the
``takes_context`` argument when registering your tag::
@register.assignment_tag(takes_context=True)
def get_current_time(context, format_string):
timezone = context['timezone']
return your_get_current_time_method(timezone, format_string)
Note that the first parameter to the function *must* be called ``context``.
For more information on how the ``takes_context`` option works, see the section
on :ref:`inclusion tags<howto-custom-template-tags-inclusion-tags>`.
``assignment_tag`` functions may accept any number of positional or keyword
arguments. For example::
@register.assignment_tag
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
...
return ...
Then in the template any number of arguments, separated by spaces, may be
passed to the template tag. Like in Python, the values for keyword arguments
are set using the equal sign ("``=``") and must be provided after the
positional arguments. For example:
.. code-block:: html+django
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile as the_result %}
Advanced custom template tags Advanced custom template tags
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -20,6 +20,8 @@ details on these changes.
* The ``django.forms.extras`` package will be removed. * The ``django.forms.extras`` package will be removed.
* The ``assignment_tag`` helper will be removed.
.. _deprecation-removed-in-2.0: .. _deprecation-removed-in-2.0:
2.0 2.0

View File

@ -137,7 +137,9 @@ Signals
Templates Templates
^^^^^^^^^ ^^^^^^^^^
* ... * Template tags created with the :meth:`~django.template.Library.simple_tag`
helper can now store results in a template variable by using the ``as``
argument.
Requests and Responses Requests and Responses
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
@ -194,6 +196,15 @@ Miscellaneous
Features deprecated in 1.9 Features deprecated in 1.9
========================== ==========================
``assignment_tag()``
~~~~~~~~~~~~~~~~~~~~
Django 1.4 added the ``assignment_tag`` helper to ease the creation of
template tags that store results in a template variable. The
:meth:`~django.template.Library.simple_tag` helper has gained this same
ability, making the ``assignment_tag`` obsolete. Tags that use
``assignment_tag`` should be updated to use ``simple_tag``.
Miscellaneous Miscellaneous
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

@ -1,4 +1,5 @@
import operator import operator
import warnings
from django import template from django import template
from django.template.defaultfilters import stringfilter from django.template.defaultfilters import stringfilter
@ -125,83 +126,17 @@ def minustwo_overridden_name(value):
register.simple_tag(lambda x: x - 1, name='minusone') register.simple_tag(lambda x: x - 1, name='minusone')
@register.assignment_tag with warnings.catch_warnings():
def assignment_no_params(): warnings.simplefilter('ignore')
"""Expected assignment_no_params __doc__"""
return "assignment_no_params - Expected result"
assignment_no_params.anything = "Expected assignment_no_params __dict__"
@register.assignment_tag
def assignment_no_params():
"""Expected assignment_no_params __doc__"""
return "assignment_no_params - Expected result"
assignment_no_params.anything = "Expected assignment_no_params __dict__"
@register.assignment_tag @register.assignment_tag(takes_context=True)
def assignment_one_param(arg): def assignment_tag_without_context_parameter(arg):
"""Expected assignment_one_param __doc__""" """Expected assignment_tag_without_context_parameter __doc__"""
return "assignment_one_param - Expected result: %s" % arg return "Expected result"
assignment_one_param.anything = "Expected assignment_one_param __dict__" assignment_tag_without_context_parameter.anything = "Expected assignment_tag_without_context_parameter __dict__"
@register.assignment_tag(takes_context=False)
def assignment_explicit_no_context(arg):
"""Expected assignment_explicit_no_context __doc__"""
return "assignment_explicit_no_context - Expected result: %s" % arg
assignment_explicit_no_context.anything = "Expected assignment_explicit_no_context __dict__"
@register.assignment_tag(takes_context=True)
def assignment_no_params_with_context(context):
"""Expected assignment_no_params_with_context __doc__"""
return "assignment_no_params_with_context - Expected result (context value: %s)" % context['value']
assignment_no_params_with_context.anything = "Expected assignment_no_params_with_context __dict__"
@register.assignment_tag(takes_context=True)
def assignment_params_and_context(context, arg):
"""Expected assignment_params_and_context __doc__"""
return "assignment_params_and_context - Expected result (context value: %s): %s" % (context['value'], arg)
assignment_params_and_context.anything = "Expected assignment_params_and_context __dict__"
@register.assignment_tag
def assignment_two_params(one, two):
"""Expected assignment_two_params __doc__"""
return "assignment_two_params - Expected result: %s, %s" % (one, two)
assignment_two_params.anything = "Expected assignment_two_params __dict__"
@register.assignment_tag
def assignment_one_default(one, two='hi'):
"""Expected assignment_one_default __doc__"""
return "assignment_one_default - Expected result: %s, %s" % (one, two)
assignment_one_default.anything = "Expected assignment_one_default __dict__"
@register.assignment_tag
def assignment_unlimited_args(one, two='hi', *args):
"""Expected assignment_unlimited_args __doc__"""
return "assignment_unlimited_args - Expected result: %s" % (', '.join(six.text_type(arg) for arg in [one, two] + list(args)))
assignment_unlimited_args.anything = "Expected assignment_unlimited_args __dict__"
@register.assignment_tag
def assignment_only_unlimited_args(*args):
"""Expected assignment_only_unlimited_args __doc__"""
return "assignment_only_unlimited_args - Expected result: %s" % ', '.join(six.text_type(arg) for arg in args)
assignment_only_unlimited_args.anything = "Expected assignment_only_unlimited_args __dict__"
@register.assignment_tag
def assignment_unlimited_args_kwargs(one, two='hi', *args, **kwargs):
"""Expected assignment_unlimited_args_kwargs __doc__"""
# Sort the dictionary by key to guarantee the order for testing.
sorted_kwarg = sorted(six.iteritems(kwargs), key=operator.itemgetter(0))
return "assignment_unlimited_args_kwargs - Expected result: %s / %s" % (
', '.join(six.text_type(arg) for arg in [one, two] + list(args)),
', '.join('%s=%s' % (k, v) for (k, v) in sorted_kwarg)
)
assignment_unlimited_args_kwargs.anything = "Expected assignment_unlimited_args_kwargs __dict__"
@register.assignment_tag(takes_context=True)
def assignment_tag_without_context_parameter(arg):
"""Expected assignment_tag_without_context_parameter __doc__"""
return "Expected result"
assignment_tag_without_context_parameter.anything = "Expected assignment_tag_without_context_parameter __dict__"

View File

@ -28,70 +28,61 @@ class CustomTagTests(TestCase):
def test_simple_tags(self): def test_simple_tags(self):
c = template.Context({'value': 42}) c = template.Context({'value': 42})
t = template.Template('{% load custom %}{% no_params %}') templates = [
self.assertEqual(t.render(c), 'no_params - Expected result') ('{% load custom %}{% no_params %}', 'no_params - Expected result'),
('{% load custom %}{% one_param 37 %}', 'one_param - Expected result: 37'),
('{% load custom %}{% explicit_no_context 37 %}', 'explicit_no_context - Expected result: 37'),
('{% load custom %}{% no_params_with_context %}',
'no_params_with_context - Expected result (context value: 42)'),
('{% load custom %}{% params_and_context 37 %}',
'params_and_context - Expected result (context value: 42): 37'),
('{% load custom %}{% simple_two_params 37 42 %}', 'simple_two_params - Expected result: 37, 42'),
('{% load custom %}{% simple_one_default 37 %}', 'simple_one_default - Expected result: 37, hi'),
('{% load custom %}{% simple_one_default 37 two="hello" %}',
'simple_one_default - Expected result: 37, hello'),
('{% load custom %}{% simple_one_default one=99 two="hello" %}',
'simple_one_default - Expected result: 99, hello'),
('{% load custom %}{% simple_one_default 37 42 %}',
'simple_one_default - Expected result: 37, 42'),
('{% load custom %}{% simple_unlimited_args 37 %}', 'simple_unlimited_args - Expected result: 37, hi'),
('{% load custom %}{% simple_unlimited_args 37 42 56 89 %}',
'simple_unlimited_args - Expected result: 37, 42, 56, 89'),
('{% load custom %}{% simple_only_unlimited_args %}', 'simple_only_unlimited_args - Expected result: '),
('{% load custom %}{% simple_only_unlimited_args 37 42 56 89 %}',
'simple_only_unlimited_args - Expected result: 37, 42, 56, 89'),
('{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 %}',
'simple_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4'),
]
t = template.Template('{% load custom %}{% one_param 37 %}') for entry in templates:
self.assertEqual(t.render(c), 'one_param - Expected result: 37') t = template.Template(entry[0])
self.assertEqual(t.render(c), entry[1])
t = template.Template('{% load custom %}{% explicit_no_context 37 %}') for entry in templates:
self.assertEqual(t.render(c), 'explicit_no_context - Expected result: 37') t = template.Template("%s as var %%}Result: {{ var }}" % entry[0][0:-2])
self.assertEqual(t.render(c), "Result: %s" % entry[1])
t = template.Template('{% load custom %}{% no_params_with_context %}') def test_simple_tag_errors(self):
self.assertEqual(t.render(c), 'no_params_with_context - Expected result (context value: 42)') errors = [
("'simple_one_default' received unexpected keyword argument 'three'",
'{% load custom %}{% simple_one_default 99 two="hello" three="foo" %}'),
("'simple_two_params' received too many positional arguments",
'{% load custom %}{% simple_two_params 37 42 56 %}'),
("'simple_one_default' received too many positional arguments",
'{% load custom %}{% simple_one_default 37 42 56 %}'),
("'simple_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)",
'{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 %}'),
("'simple_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'",
'{% load custom %}{% simple_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" %}'),
]
t = template.Template('{% load custom %}{% params_and_context 37 %}') for entry in errors:
self.assertEqual(t.render(c), 'params_and_context - Expected result (context value: 42): 37') six.assertRaisesRegex(self, template.TemplateSyntaxError, entry[0], template.Template, entry[1])
t = template.Template('{% load custom %}{% simple_two_params 37 42 %}') for entry in errors:
self.assertEqual(t.render(c), 'simple_two_params - Expected result: 37, 42') six.assertRaisesRegex(
self, template.TemplateSyntaxError, entry[0], template.Template, "%s as var %%}" % entry[1][0:-2],
t = template.Template('{% load custom %}{% simple_one_default 37 %}') )
self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, hi')
t = template.Template('{% load custom %}{% simple_one_default 37 two="hello" %}')
self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, hello')
t = template.Template('{% load custom %}{% simple_one_default one=99 two="hello" %}')
self.assertEqual(t.render(c), 'simple_one_default - Expected result: 99, hello')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'simple_one_default' received unexpected keyword argument 'three'",
template.Template, '{% load custom %}{% simple_one_default 99 two="hello" three="foo" %}')
t = template.Template('{% load custom %}{% simple_one_default 37 42 %}')
self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, 42')
t = template.Template('{% load custom %}{% simple_unlimited_args 37 %}')
self.assertEqual(t.render(c), 'simple_unlimited_args - Expected result: 37, hi')
t = template.Template('{% load custom %}{% simple_unlimited_args 37 42 56 89 %}')
self.assertEqual(t.render(c), 'simple_unlimited_args - Expected result: 37, 42, 56, 89')
t = template.Template('{% load custom %}{% simple_only_unlimited_args %}')
self.assertEqual(t.render(c), 'simple_only_unlimited_args - Expected result: ')
t = template.Template('{% load custom %}{% simple_only_unlimited_args 37 42 56 89 %}')
self.assertEqual(t.render(c), 'simple_only_unlimited_args - Expected result: 37, 42, 56, 89')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'simple_two_params' received too many positional arguments",
template.Template, '{% load custom %}{% simple_two_params 37 42 56 %}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'simple_one_default' received too many positional arguments",
template.Template, '{% load custom %}{% simple_one_default 37 42 56 %}')
t = template.Template('{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 %}')
self.assertEqual(t.render(c), 'simple_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'simple_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)",
template.Template, '{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 %}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'simple_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'",
template.Template, '{% load custom %}{% simple_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" %}')
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.
@ -278,102 +269,9 @@ class CustomTagTests(TestCase):
t = template.Template('{% load custom %}{% assignment_no_params as var %}The result is: {{ var }}') t = template.Template('{% 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')
t = template.Template('{% load custom %}{% assignment_one_param 37 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_one_param - Expected result: 37')
t = template.Template('{% load custom %}{% assignment_explicit_no_context 37 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_explicit_no_context - Expected result: 37')
t = template.Template('{% load custom %}{% assignment_no_params_with_context as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_no_params_with_context - Expected result (context value: 42)')
t = template.Template('{% load custom %}{% assignment_params_and_context 37 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_params_and_context - Expected result (context value: 42): 37')
t = template.Template('{% load custom %}{% assignment_two_params 37 42 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_two_params - Expected result: 37, 42')
t = template.Template('{% load custom %}{% assignment_one_default 37 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, hi')
t = template.Template('{% load custom %}{% assignment_one_default 37 two="hello" as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, hello')
t = template.Template('{% load custom %}{% assignment_one_default one=99 two="hello" as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 99, hello')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_one_default' received unexpected keyword argument 'three'",
template.Template, '{% load custom %}{% assignment_one_default 99 two="hello" three="foo" as var %}')
t = template.Template('{% load custom %}{% assignment_one_default 37 42 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, 42')
t = template.Template('{% load custom %}{% assignment_unlimited_args 37 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args - Expected result: 37, hi')
t = template.Template('{% load custom %}{% assignment_unlimited_args 37 42 56 89 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args - Expected result: 37, 42, 56, 89')
t = template.Template('{% load custom %}{% assignment_only_unlimited_args as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_only_unlimited_args - Expected result: ')
t = template.Template('{% load custom %}{% assignment_only_unlimited_args 37 42 56 89 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_only_unlimited_args - Expected result: 37, 42, 56, 89')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'",
template.Template, '{% load custom %}{% assignment_one_param 37 %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'",
template.Template, '{% load custom %}{% assignment_one_param 37 as %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'",
template.Template, '{% load custom %}{% assignment_one_param 37 ass var %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_two_params' received too many positional arguments",
template.Template, '{% load custom %}{% assignment_two_params 37 42 56 as var %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_one_default' received too many positional arguments",
template.Template, '{% load custom %}{% assignment_one_default 37 42 56 as var %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_one_default' did not receive value\(s\) for the argument\(s\): 'one'",
template.Template, '{% load custom %}{% assignment_one_default as var %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_unlimited_args' did not receive value\(s\) for the argument\(s\): 'one'",
template.Template, '{% load custom %}{% assignment_unlimited_args as var %}The result is: {{ var }}')
t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 as var %}The result is: {{ var }}')
self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)",
template.Template, '{% load custom %}{% assignment_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 as var %}The result is: {{ var }}')
six.assertRaisesRegex(self, template.TemplateSyntaxError,
"'assignment_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'",
template.Template, '{% load custom %}{% assignment_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" as var %}The result is: {{ var }}')
def test_assignment_tag_registration(self): def test_assignment_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.
self.verify_tag(custom.assignment_no_params, 'assignment_no_params') self.verify_tag(custom.assignment_no_params, 'assignment_no_params')
self.verify_tag(custom.assignment_one_param, 'assignment_one_param')
self.verify_tag(custom.assignment_explicit_no_context, 'assignment_explicit_no_context')
self.verify_tag(custom.assignment_no_params_with_context, 'assignment_no_params_with_context')
self.verify_tag(custom.assignment_params_and_context, 'assignment_params_and_context')
self.verify_tag(custom.assignment_one_default, 'assignment_one_default')
self.verify_tag(custom.assignment_two_params, 'assignment_two_params')
self.verify_tag(custom.assignment_unlimited_args, 'assignment_unlimited_args')
self.verify_tag(custom.assignment_only_unlimited_args, 'assignment_only_unlimited_args')
self.verify_tag(custom.assignment_unlimited_args, 'assignment_unlimited_args')
self.verify_tag(custom.assignment_unlimited_args_kwargs, 'assignment_unlimited_args_kwargs')
self.verify_tag(custom.assignment_tag_without_context_parameter, 'assignment_tag_without_context_parameter')
def test_assignment_tag_missing_context(self): def test_assignment_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