diff options
| author | Jake Howard <git@theorangeone.net> | 2025-11-12 17:41:32 +0000 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-12-05 10:06:48 -0500 |
| commit | 0ac548635eee801d5de49bec482b7b8e1e97ef59 (patch) | |
| tree | cfa0aa9b73c8d0a5e614fe8c8cc6adbc7d3a2efb /django | |
| parent | 55888655a269f41025405b9a1bff14117ae58e2a (diff) | |
Fixed #36728 -- Validated template tag arguments at definition time.
Before, `context` and `content` were validated at compile time.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/admin/templatetags/admin_list.py | 7 | ||||
| -rw-r--r-- | django/contrib/admin/templatetags/admin_modify.py | 4 | ||||
| -rw-r--r-- | django/contrib/admin/templatetags/base.py | 13 | ||||
| -rw-r--r-- | django/template/library.py | 68 |
4 files changed, 60 insertions, 32 deletions
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 2100f93566..52aae9e589 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -76,6 +76,7 @@ def pagination(cl): @register.tag(name="pagination") def pagination_tag(parser, token): return InclusionAdminNode( + "pagination", parser, token, func=pagination, @@ -361,6 +362,7 @@ def result_list(cl): @register.tag(name="result_list") def result_list_tag(parser, token): return InclusionAdminNode( + "result_list", parser, token, func=result_list, @@ -481,6 +483,7 @@ def date_hierarchy(cl): @register.tag(name="date_hierarchy") def date_hierarchy_tag(parser, token): return InclusionAdminNode( + "date_hierarchy", parser, token, func=date_hierarchy, @@ -505,6 +508,7 @@ def search_form(cl): @register.tag(name="search_form") def search_form_tag(parser, token): return InclusionAdminNode( + "search_form", parser, token, func=search_form, @@ -537,7 +541,7 @@ def admin_actions(context): @register.tag(name="admin_actions") def admin_actions_tag(parser, token): return InclusionAdminNode( - parser, token, func=admin_actions, template_name="actions.html" + "admin_actions", parser, token, func=admin_actions, template_name="actions.html" ) @@ -545,6 +549,7 @@ def admin_actions_tag(parser, token): def change_list_object_tools_tag(parser, token): """Display the row of change list object tools.""" return InclusionAdminNode( + "change_list_object_tools", parser, token, func=lambda context: context, diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index 0e3046ae5a..c3d2ad01d9 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -51,6 +51,7 @@ def prepopulated_fields_js(context): @register.tag(name="prepopulated_fields_js") def prepopulated_fields_js_tag(parser, token): return InclusionAdminNode( + "prepopulated_fields_js", parser, token, func=prepopulated_fields_js, @@ -115,7 +116,7 @@ def submit_row(context): @register.tag(name="submit_row") def submit_row_tag(parser, token): return InclusionAdminNode( - parser, token, func=submit_row, template_name="submit_line.html" + "submit_row", parser, token, func=submit_row, template_name="submit_line.html" ) @@ -123,6 +124,7 @@ def submit_row_tag(parser, token): def change_form_object_tools_tag(parser, token): """Display the row of change form object tools.""" return InclusionAdminNode( + "change_form_object_tools", parser, token, func=lambda context: context, diff --git a/django/contrib/admin/templatetags/base.py b/django/contrib/admin/templatetags/base.py index 3f8290d3b1..c0474135ea 100644 --- a/django/contrib/admin/templatetags/base.py +++ b/django/contrib/admin/templatetags/base.py @@ -1,5 +1,6 @@ from inspect import getfullargspec +from django.template.exceptions import TemplateSyntaxError from django.template.library import InclusionNode, parse_bits from django.utils.inspect import lazy_annotations @@ -10,12 +11,21 @@ class InclusionAdminNode(InclusionNode): or globally. """ - def __init__(self, parser, token, func, template_name, takes_context=True): + def __init__(self, name, parser, token, func, template_name, takes_context=True): self.template_name = template_name with lazy_annotations(): params, varargs, varkw, defaults, kwonly, kwonly_defaults, _ = ( getfullargspec(func) ) + if takes_context: + if params and params[0] == "context": + del params[0] + else: + function_name = func.__name__ + raise TemplateSyntaxError( + f"{name!r} sets takes_context=True so {function_name!r} " + "must have a first argument of 'context'" + ) bits = token.split_contents() args, kwargs = parse_bits( parser, @@ -26,7 +36,6 @@ class InclusionAdminNode(InclusionNode): defaults, kwonly, kwonly_defaults, - takes_context, bits[0], ) super().__init__(func, takes_context, args, kwargs, filename=None) diff --git a/django/template/library.py b/django/template/library.py index 27af7a6969..0a459c0497 100644 --- a/django/template/library.py +++ b/django/template/library.py @@ -123,6 +123,15 @@ class Library: ) = getfullargspec(unwrap(func)) function_name = name or func.__name__ + if takes_context: + if params and params[0] == "context": + del params[0] + else: + raise TemplateSyntaxError( + f"{function_name!r} is decorated with takes_context=True so it " + "must have a first argument of 'context'" + ) + @wraps(func) def compile_func(parser, token): bits = token.split_contents()[1:] @@ -139,7 +148,6 @@ class Library: defaults, kwonly, kwonly_defaults, - takes_context, function_name, ) return SimpleNode(func, takes_context, args, kwargs, target_var) @@ -182,26 +190,32 @@ class Library: if end_name is None: end_name = f"end{function_name}" - @wraps(func) - def compile_func(parser, token): - tag_params = params.copy() + if takes_context: + if len(params) >= 2 and params[1] == "content": + del params[1] + else: + raise TemplateSyntaxError( + f"{function_name!r} is decorated with takes_context=True so" + " it must have a first argument of 'context' and a second " + "argument of 'content'" + ) - if takes_context: - if len(tag_params) >= 2 and tag_params[1] == "content": - del tag_params[1] - else: - raise TemplateSyntaxError( - f"{function_name!r} is decorated with takes_context=True so" - " it must have a first argument of 'context' and a second " - "argument of 'content'" - ) - elif tag_params and tag_params[0] == "content": - del tag_params[0] + if params and params[0] == "context": + del params[0] else: raise TemplateSyntaxError( - f"'{function_name}' must have a first argument of 'content'" + f"{function_name!r} is decorated with takes_context=True so it " + "must have a first argument of 'context'" ) + elif params and params[0] == "content": + del params[0] + else: + raise TemplateSyntaxError( + f"{function_name!r} must have a first argument of 'content'" + ) + @wraps(func) + def compile_func(parser, token): bits = token.split_contents()[1:] target_var = None if len(bits) >= 2 and bits[-2] == "as": @@ -214,13 +228,12 @@ class Library: args, kwargs = parse_bits( parser, bits, - tag_params, + params, varargs, varkw, defaults, kwonly, kwonly_defaults, - takes_context, function_name, ) @@ -263,6 +276,15 @@ class Library: ) = getfullargspec(unwrap(func)) function_name = name or func.__name__ + if takes_context: + if params and params[0] == "context": + params = params[1:] + else: + raise TemplateSyntaxError( + f"{function_name!r} is decorated with takes_context=True so it " + "must have a first argument of 'context'" + ) + @wraps(func) def compile_func(parser, token): bits = token.split_contents()[1:] @@ -275,7 +297,6 @@ class Library: defaults, kwonly, kwonly_defaults, - takes_context, function_name, ) return InclusionNode( @@ -394,7 +415,6 @@ def parse_bits( defaults, kwonly, kwonly_defaults, - takes_context, name, ): """ @@ -402,14 +422,6 @@ def parse_bits( particular by detecting syntax errors and by extracting positional and keyword arguments. """ - if takes_context: - if params and params[0] == "context": - params = params[1:] - else: - raise TemplateSyntaxError( - "'%s' is decorated with takes_context=True so it must " - "have a first argument of 'context'" % name - ) args = [] kwargs = {} unhandled_params = list(params) |
