From cd4282816db9164791cd0ac97a3dc329ad92c522 Mon Sep 17 00:00:00 2001 From: Preston Timmons Date: Fri, 16 Jan 2015 17:34:32 -0600 Subject: [PATCH] Fixed #18651 -- Enabled optional assignments for simple_tag(). --- django/template/base.py | 85 ++++---- docs/howto/custom-template-tags.txt | 56 ++---- docs/internals/deprecation.txt | 2 + docs/releases/1.9.txt | 13 +- tests/template_tests/templatetags/custom.py | 91 ++------- tests/template_tests/test_custom.py | 202 +++++--------------- 6 files changed, 130 insertions(+), 319 deletions(-) diff --git a/django/template/base.py b/django/template/base.py index 6594af1e1a..775b5d8238 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -61,7 +61,8 @@ from django.apps import apps from django.template.context import (BaseContext, Context, RequestContext, # NOQA: imported for backwards compatibility ContextPopException) 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.text import (smart_split, unescape_string_literal, get_text_list) @@ -1021,9 +1022,9 @@ def token_kwargs(bits, parser, support_legacy=False): def parse_bits(parser, bits, params, varargs, varkw, defaults, takes_context, name): """ - Parses bits for template tag helpers (simple_tag, include_tag and - assignment_tag), in particular by detecting syntax errors and by - extracting positional and keyword arguments. + Parses bits for template tag helpers simple_tag and inclusion_tag, in + particular by detecting syntax errors and by extracting positional and + keyword arguments. """ if takes_context: if params[0] == 'context': @@ -1099,9 +1100,9 @@ def generic_tag_compiler(parser, token, params, varargs, varkw, defaults, class TagHelperNode(Node): """ - Base class for tag helper nodes such as SimpleNode, InclusionNode and - AssignmentNode. Manages the positional and keyword arguments to be passed - to the decorated function. + Base class for tag helper nodes such as SimpleNode and InclusionNode. + Manages the positional and keyword arguments to be passed to the decorated + function. """ def __init__(self, takes_context, args, kwargs): @@ -1191,17 +1192,31 @@ class Library(object): params, varargs, varkw, defaults = getargspec(func) 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): 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 getattr(func, '_decorated_function', func).__name__) - compile_func = partial(generic_tag_compiler, - params=params, varargs=varargs, varkw=varkw, - defaults=defaults, name=function_name, - takes_context=takes_context, node_class=SimpleNode) + + def compile_func(parser, token): + bits = token.split_contents()[1:] + 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__ self.tag(function_name, compile_func) return func @@ -1216,46 +1231,12 @@ class Library(object): raise TemplateSyntaxError("Invalid arguments provided to simple_tag") def assignment_tag(self, func=None, takes_context=None, name=None): - def dec(func): - params, varargs, varkw, defaults = getargspec(func) - - class AssignmentNode(TagHelperNode): - def __init__(self, takes_context, args, kwargs, target_var): - super(AssignmentNode, self).__init__(takes_context, args, kwargs) - 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") + warnings.warn( + "assignment_tag() is deprecated. Use simple_tag() instead", + RemovedInDjango21Warning, + stacklevel=2, + ) + return self.simple_tag(func, takes_context, name) def inclusion_tag(self, file_name, takes_context=False, name=None): def dec(func): diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt index b13c8cb81a..e4fe6949ea 100644 --- a/docs/howto/custom-template-tags.txt +++ b/docs/howto/custom-template-tags.txt @@ -388,7 +388,7 @@ Simple tags .. method:: django.template.Library.simple_tag() 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 ``current_time`` tag might accept a format string and return the time as a string formatted accordingly. @@ -459,6 +459,18 @@ positional arguments. For example: {% 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 %} +

The time is {{ the_time }}.

+ .. _howto-custom-template-tags-inclusion-tags: Inclusion tags @@ -602,11 +614,15 @@ Assignment tags .. 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 a helper function, ``assignment_tag``. This function works the same way as -:ref:`simple_tag`, except that it -stores the tag's result in a specified context variable instead of directly -outputting it. +:meth:`~django.template.Library.simple_tag` except that it stores the tag's +result in a specified context variable instead of directly outputting it. 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 %}

The time is {{ the_time }}.

-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`. - -``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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 50782b363c..66477109ec 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -20,6 +20,8 @@ details on these changes. * The ``django.forms.extras`` package will be removed. +* The ``assignment_tag`` helper will be removed. + .. _deprecation-removed-in-2.0: 2.0 diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index 8c7aff8fe1..db9b6c324d 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -137,7 +137,9 @@ Signals 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 ^^^^^^^^^^^^^^^^^^^^^^ @@ -194,6 +196,15 @@ Miscellaneous 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 ~~~~~~~~~~~~~ diff --git a/tests/template_tests/templatetags/custom.py b/tests/template_tests/templatetags/custom.py index 953af07ef1..50ebd353ec 100644 --- a/tests/template_tests/templatetags/custom.py +++ b/tests/template_tests/templatetags/custom.py @@ -1,4 +1,5 @@ import operator +import warnings from django import template 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.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__" +with warnings.catch_warnings(): + warnings.simplefilter('ignore') + @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 -def assignment_one_param(arg): - """Expected assignment_one_param __doc__""" - return "assignment_one_param - Expected result: %s" % arg -assignment_one_param.anything = "Expected assignment_one_param __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__" + @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__" diff --git a/tests/template_tests/test_custom.py b/tests/template_tests/test_custom.py index 77d089661f..66bb3fd156 100644 --- a/tests/template_tests/test_custom.py +++ b/tests/template_tests/test_custom.py @@ -28,70 +28,61 @@ class CustomTagTests(TestCase): def test_simple_tags(self): c = template.Context({'value': 42}) - t = template.Template('{% load custom %}{% no_params %}') - self.assertEqual(t.render(c), 'no_params - Expected result') + templates = [ + ('{% 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 %}') - self.assertEqual(t.render(c), 'one_param - Expected result: 37') + for entry in templates: + t = template.Template(entry[0]) + self.assertEqual(t.render(c), entry[1]) - t = template.Template('{% load custom %}{% explicit_no_context 37 %}') - self.assertEqual(t.render(c), 'explicit_no_context - Expected result: 37') + for entry in templates: + 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 %}') - self.assertEqual(t.render(c), 'no_params_with_context - Expected result (context value: 42)') + def test_simple_tag_errors(self): + 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 %}') - self.assertEqual(t.render(c), 'params_and_context - Expected result (context value: 42): 37') + for entry in errors: + six.assertRaisesRegex(self, template.TemplateSyntaxError, entry[0], template.Template, entry[1]) - t = template.Template('{% load custom %}{% simple_two_params 37 42 %}') - self.assertEqual(t.render(c), 'simple_two_params - Expected result: 37, 42') - - 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" %}') + for entry in errors: + six.assertRaisesRegex( + self, template.TemplateSyntaxError, entry[0], template.Template, "%s as var %%}" % entry[1][0:-2], + ) def test_simple_tag_registration(self): # 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 }}') 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): # 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_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): # The 'context' parameter must be present when takes_context is True