Opened 13 months ago

Last modified 13 months ago

#34609 closed Cleanup/optimization

Deprecate format_html calls without args or kwargs — at Version 5

Reported by: Adam Johnson Owned by: Bhuvnesh
Component: Utilities Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Michael Howitz)

In my experience, a common misuse of format_html is to format the HTML before calling it:

format_html(f"<i>{name}</i>")

This makes it act like mark_safe, allowing data through without escaping. It provides a false sense of security since format_html is meant to be the "safe way".

I propose we deprecate calls to format_html that don’t pass args or kwargs, and eventually raise a TypeError for such cases.

(Following improvement to format_html docs in #34595.)

Change History (5)

comment:1 by Adam Johnson, 13 months ago

Description: modified (diff)

comment:2 by Mariusz Felisiak, 13 months ago

Triage Stage: Unreviewed β†’ Accepted

comment:3 by Bhuvnesh, 13 months ago

  • django/utils/html.py

    diff --git a/django/utils/html.py b/django/utils/html.py
    index c32a36fa93..b2a0c3d3db 100644
    a b def format_html(format_string, *args, **kwargs):  
    100100    and call mark_safe() on the result. This function should be used instead
    101101    of str.format or % interpolation to build up small HTML fragments.
    102102    """
     103    if not (args or kwargs):
     104        raise TypeError("Arguments are missing.")
    103105    args_safe = map(conditional_escape, args)
    104106    kwargs_safe = {k: conditional_escape(v) for (k, v) in kwargs.items()}
    105107    return mark_safe(format_string.format(*args_safe, **kwargs_safe))
  • tests/utils_tests/test_html.py

    diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py
    index b7a7396075..c83fe7ddf6 100644
    a b class TestUtilsHtml(SimpleTestCase):  
    6565            "&lt; Dangerous &gt; <b>safe</b> &lt; dangerous again <i>safe again</i>",
    6666        )
    6767
     68    def test_format_html_no_args(self):
     69        msg = "Arguments are missing."
     70        with self.assertRaisesMessage(TypeError, msg):
     71            self.assertEqual(
     72                format_html(
     73                    "<i>{name}</i>",
     74                ),
     75                "<i>Adam</i>",
     76            )
     77
    6878    def test_linebreaks(self):
    6979        items = (
    7080            ("para1\n\npara2\r\rpara3", "<p>para1</p>\n\n<p>para2</p>\n\n<p>para3</p>"),

Are these changes relevant? I don't have much experience with templates, still a lot to learn .πŸ˜…

comment:4 by Bhuvnesh, 13 months ago

Owner: changed from nobody to Bhuvnesh
Status: new β†’ assigned

comment:5 by Michael Howitz, 13 months ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top