From 15fd589c6b37d01d10d001882827bda332fcb00b Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sat, 24 Aug 2024 16:26:46 +0100 Subject: [PATCH] Update simple tag implementation from Django PR --- yamdl_playground/core/simple_tags.py | 73 ++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/yamdl_playground/core/simple_tags.py b/yamdl_playground/core/simple_tags.py index b493551..0958c53 100644 --- a/yamdl_playground/core/simple_tags.py +++ b/yamdl_playground/core/simple_tags.py @@ -1,5 +1,6 @@ from inspect import getfullargspec, unwrap from django.template.library import parse_bits, SimpleNode +from django.template.exceptions import TemplateSyntaxError from functools import wraps class SimpleBlockNode(SimpleNode): @@ -9,43 +10,77 @@ class SimpleBlockNode(SimpleNode): def get_resolved_arguments(self, context): resolved_args, resolved_kwargs = super().get_resolved_arguments(context) - resolved_args.insert(1 if self.takes_context else 0, self.nodelist.render(context)) + + # Restore the "content" argument. + # It will move depending on whether takes_context was passed. + resolved_args.insert( + 1 if self.takes_context else 0, self.nodelist.render(context) + ) + return resolved_args, resolved_kwargs def simple_block_tag(register, takes_context=None, name=None): def dec(func): - argspec = getfullargspec(unwrap(func)) + ( + params, + varargs, + varkw, + defaults, + kwonly, + kwonly_defaults, + _, + ) = getfullargspec(unwrap(func)) function_name = name or func.__name__ @wraps(func) - def tag_compiler(parser, token): + def compile_func(parser, token): + tag_params = params.copy() + + if takes_context: + if len(tag_params) >= 2 and tag_params[1] == "content": + del tag_params[1] + else: + raise TemplateSyntaxError( + f"'{function_name}' is decorated with takes_context=True so" + " it must have a first argument of 'context' and a second " + "argument of 'content'" + ) + else: + if tag_params and tag_params[0] == "content": + del tag_params[0] + else: + raise TemplateSyntaxError( + f"'{function_name}' must have a first argument of 'content'" + ) + bits = token.split_contents()[1:] target_var = None if len(bits) >= 2 and bits[-2] == "as": target_var = bits[-1] bits = bits[:-2] - params = argspec.args - del params[1 if takes_context else 0] + nodelist = parser.parse((f"end{function_name}",)) + parser.delete_first_token() args, kwargs = parse_bits( - parser=parser, - bits=bits, - params=params, - varargs=argspec.varargs, - varkw=argspec.varkw, - defaults=argspec.defaults, - kwonly=argspec.kwonlyargs, - kwonly_defaults=argspec.kwonlydefaults, - takes_context=takes_context, - name=function_name + parser, + bits, + tag_params, + varargs, + varkw, + defaults, + kwonly, + kwonly_defaults, + takes_context, + function_name, ) - nodelist = parser.parse((f'end{function_name}',)) - parser.delete_first_token() - return SimpleBlockNode(nodelist, func, takes_context, args, kwargs, target_var) + return SimpleBlockNode( + nodelist, func, takes_context, args, kwargs, target_var + ) - register.tag(function_name, tag_compiler) + register.tag(function_name, compile_func) return func + return dec