From 775975f15d7d461c154e558cba5fb0592539126f Mon Sep 17 00:00:00 2001 From: Erik Romijn Date: Sat, 1 Mar 2014 10:42:08 +0100 Subject: [PATCH] Fixed #22130 -- Deprecated fix_ampersands, removed utils.clean_html() --- django/utils/html.py | 7 +++++ docs/internals/deprecation.txt | 3 ++ docs/ref/templates/builtins.txt | 3 ++ docs/releases/1.7.txt | 13 +++++++++ tests/defaultfilters/tests.py | 8 ++++-- tests/template_tests/tests.py | 5 +++- tests/utils_tests/test_html.py | 49 +++++++++++++++++++-------------- 7 files changed, 64 insertions(+), 24 deletions(-) diff --git a/django/utils/html.py b/django/utils/html.py index b6b639d538..a08b62ff5e 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import re +import warnings from django.utils.safestring import SafeData, mark_safe from django.utils.encoding import force_text, force_str @@ -174,6 +175,9 @@ strip_entities = allow_lazy(strip_entities, six.text_type) def fix_ampersands(value): """Returns the given HTML with all unencoded ampersands encoded correctly.""" + # As fix_ampersands is wrapped in allow_lazy, stacklevel 3 is more useful than 2. + warnings.warn("The fix_ampersands function is deprecated and will be removed in Django 1.8.", + DeprecationWarning, stacklevel=3) return unencoded_ampersands_re.sub('&', force_text(value)) fix_ampersands = allow_lazy(fix_ampersands, six.text_type) @@ -290,6 +294,9 @@ def clean_html(text): * Remove stuff like "

  

", but only if it's at the bottom of the text. """ + # As clean_html is wrapped in allow_lazy, stacklevel 3 is more useful than 2. + warnings.warn("The clean_html function is deprecated and will be removed in Django 1.8.", + DeprecationWarning, stacklevel=3) text = normalize_newlines(text) text = re.sub(r'<(/?)\s*b\s*>', '<\\1strong>', text) text = re.sub(r'<(/?)\s*i\s*>', '<\\1em>', text) diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index f64cc53d25..36bc2ee533 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -209,6 +209,9 @@ details on these changes. (``django.contrib.gis.sitemaps.views.index`` and ``django.contrib.gis.sitemaps.views.sitemap``). +* ``django.utils.html.fix_ampersands``, the ``fix_ampersands`` template filter and + ``django.utils.html.clean_html`` will be removed following an accelerated deprecation. + .. _deprecation-removed-in-1.7: 1.7 diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index a5d4c7c26e..bb02187727 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1582,6 +1582,9 @@ fix_ampersands This is rarely useful as ampersands are automatically escaped. See :tfilter:`escape` for more information. +.. deprecated:: 1.7 + This filter has been deprecated and will be removed in Django 1.8. + Replaces ampersands with ``&`` entities. For example:: diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 98b336f630..882fa69dee 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -1406,3 +1406,16 @@ strings, you should use ``django.utils.html.escapejs`` or the :tfilter:`escapejs` template filter. If all you need is to generate valid javascript strings, you can simply use ``json.dumps()``. + +``fix_ampersands`` utils method and template filter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``django.utils.html.fix_ampersands`` method and the :tfilter:`fix_ampersands` +template filter are deprecated, as the escaping of ampersands is already taken care +of by Django's standard HTML escaping features. Combining this with ``fix_ampersands`` +would either result in double escaping, or, if the output is assumed to be safe, +a risk of introducing XSS vulnerabilities. Along with ``fix_ampersands``, +``django.utils.html.clean_html`` is deprecated, an undocumented function that calls +``fix_ampersands``. +As this is an accelerated deprecation, ``fix_ampersands`` and ``clean_html`` +will be removed in Django 1.8. diff --git a/tests/defaultfilters/tests.py b/tests/defaultfilters/tests.py index f10b1c3305..5ff31cc025 100644 --- a/tests/defaultfilters/tests.py +++ b/tests/defaultfilters/tests.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import datetime import decimal import unittest +import warnings from django.template.defaultfilters import ( add, addslashes, capfirst, center, cut, date, default, default_if_none, @@ -124,8 +125,11 @@ class DefaultFiltersTests(TestCase): 'paragraph separator:\\u2029and line separator:\\u2028') def test_fix_ampersands(self): - self.assertEqual(fix_ampersands_filter('Jack & Jill & Jeroboam'), - 'Jack & Jill & Jeroboam') + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", DeprecationWarning) + self.assertEqual(fix_ampersands_filter('Jack & Jill & Jeroboam'), + 'Jack & Jill & Jeroboam') + self.assertEqual(len(w), 1) def test_linenumbers(self): self.assertEqual(linenumbers('line 1\nline 2'), diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index dee11e4bba..1a0e0d4456 100644 --- a/tests/template_tests/tests.py +++ b/tests/template_tests/tests.py @@ -607,7 +607,10 @@ class TemplateTests(TestCase): failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template loading invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name)) try: - output = self.render(test_template, vals) + with warnings.catch_warnings(): + # Ignore deprecation of fix_ampersands + warnings.filterwarnings("ignore", category=DeprecationWarning, module='django.template.defaultfilters') + output = self.render(test_template, vals) except ShouldNotExecuteException: failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template rendering invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name)) except ContextStackException: diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py index cafdee5c03..3f316e1a8b 100644 --- a/tests/utils_tests/test_html.py +++ b/tests/utils_tests/test_html.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals from datetime import datetime import os from unittest import TestCase +import warnings from django.utils import html, safestring from django.utils._os import upath @@ -130,25 +131,29 @@ class TestUtilsHtml(TestCase): self.check_output(f, in_pattern % {'entity': entity}, output) def test_fix_ampersands(self): - f = html.fix_ampersands - # Strings without ampersands or with ampersands already encoded. - values = ("a", "b", "&a;", "& &x; ", "asdf") - patterns = ( - ("%s", "%s"), - ("&%s", "&%s"), - ("&%s&", "&%s&"), - ) - for value in values: - for in_pattern, out_pattern in patterns: - self.check_output(f, in_pattern % value, out_pattern % value) - # Strings with ampersands that need encoding. - items = ( - ("&#;", "&#;"), - ("ͫ ;", "&#875 ;"), - ("abc;", "&#4abc;"), - ) - for value, output in items: - self.check_output(f, value, output) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + f = html.fix_ampersands + # Strings without ampersands or with ampersands already encoded. + values = ("a", "b", "&a;", "& &x; ", "asdf") + patterns = ( + ("%s", "%s"), + ("&%s", "&%s"), + ("&%s&", "&%s&"), + ) + + for value in values: + for in_pattern, out_pattern in patterns: + self.check_output(f, in_pattern % value, out_pattern % value) + + # Strings with ampersands that need encoding. + items = ( + ("&#;", "&#;"), + ("ͫ ;", "&#875 ;"), + ("abc;", "&#4abc;"), + ) + for value, output in items: + self.check_output(f, value, output) def test_escapejs(self): f = html.escapejs @@ -171,8 +176,10 @@ class TestUtilsHtml(TestCase): # also a regression test for #7267: this used to raise an UnicodeDecodeError ('

* foo

* bar

', ''), ) - for value, output in items: - self.check_output(f, value, output) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + for value, output in items: + self.check_output(f, value, output) def test_remove_tags(self): f = html.remove_tags