summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorAlexander Allakhverdiyev <alex.allah@gmail.com>2017-05-11 07:09:44 -0700
committerTim Graham <timograham@gmail.com>2017-05-11 10:09:44 -0400
commita7c6c705e82bfb9f061f35d38c2a6184dae52cd4 (patch)
treef97076bf7e08ef7cb05ebf323a7014e06ff05338 /django
parentf87256b15e375c6c57fe425c33ae23e116da3e84 (diff)
Fixed #28129 -- Allowed custom template tags to use keyword-only arguments.
Diffstat (limited to 'django')
-rw-r--r--django/template/library.py23
1 files changed, 15 insertions, 8 deletions
diff --git a/django/template/library.py b/django/template/library.py
index c319a04340..f88c2af822 100644
--- a/django/template/library.py
+++ b/django/template/library.py
@@ -106,7 +106,7 @@ class Library:
return 'world'
"""
def dec(func):
- params, varargs, varkw, defaults, _, _, _ = getfullargspec(func)
+ params, varargs, varkw, defaults, kwonly, kwonly_defaults, _ = getfullargspec(func)
function_name = (name or getattr(func, '_decorated_function', func).__name__)
@functools.wraps(func)
@@ -118,7 +118,7 @@ class Library:
bits = bits[:-2]
args, kwargs = parse_bits(
parser, bits, params, varargs, varkw, defaults,
- takes_context, function_name
+ kwonly, kwonly_defaults, takes_context, function_name,
)
return SimpleNode(func, takes_context, args, kwargs, target_var)
self.tag(function_name, compile_func)
@@ -143,7 +143,7 @@ class Library:
return {'choices': choices}
"""
def dec(func):
- params, varargs, varkw, defaults, _, _, _ = getfullargspec(func)
+ params, varargs, varkw, defaults, kwonly, kwonly_defaults, _ = getfullargspec(func)
function_name = (name or getattr(func, '_decorated_function', func).__name__)
@functools.wraps(func)
@@ -151,7 +151,7 @@ class Library:
bits = token.split_contents()[1:]
args, kwargs = parse_bits(
parser, bits, params, varargs, varkw, defaults,
- takes_context, function_name,
+ kwonly, kwonly_defaults, takes_context, function_name,
)
return InclusionNode(
func, takes_context, args, kwargs, filename,
@@ -235,7 +235,7 @@ class InclusionNode(TagHelperNode):
def parse_bits(parser, bits, params, varargs, varkw, defaults,
- takes_context, name):
+ kwonly, kwonly_defaults, takes_context, name):
"""
Parse bits for template tag helpers simple_tag and inclusion_tag, in
particular by detecting syntax errors and by extracting positional and
@@ -251,13 +251,17 @@ def parse_bits(parser, bits, params, varargs, varkw, defaults,
args = []
kwargs = {}
unhandled_params = list(params)
+ unhandled_kwargs = [
+ kwarg for kwarg in kwonly
+ if not kwonly_defaults or kwarg not in kwonly_defaults
+ ]
for bit in bits:
# First we try to extract a potential kwarg from the bit
kwarg = token_kwargs([bit], parser)
if kwarg:
# The kwarg was successfully extracted
param, value = kwarg.popitem()
- if param not in params and varkw is None:
+ if param not in params and param not in unhandled_kwargs and varkw is None:
# An unexpected keyword argument was supplied
raise TemplateSyntaxError(
"'%s' received unexpected keyword argument '%s'" %
@@ -274,6 +278,9 @@ def parse_bits(parser, bits, params, varargs, varkw, defaults,
# If using the keyword syntax for a positional arg, then
# consume it.
unhandled_params.remove(param)
+ elif param in unhandled_kwargs:
+ # Same for keyword-only arguments
+ unhandled_kwargs.remove(param)
else:
if kwargs:
raise TemplateSyntaxError(
@@ -294,11 +301,11 @@ def parse_bits(parser, bits, params, varargs, varkw, defaults,
# Consider the last n params handled, where n is the
# number of defaults.
unhandled_params = unhandled_params[:-len(defaults)]
- if unhandled_params:
+ if unhandled_params or unhandled_kwargs:
# Some positional arguments were not supplied
raise TemplateSyntaxError(
"'%s' did not receive value(s) for the argument(s): %s" %
- (name, ", ".join("'%s'" % p for p in unhandled_params)))
+ (name, ", ".join("'%s'" % p for p in unhandled_params + unhandled_kwargs)))
return args, kwargs