Commit af64429b authored by Unai Zalakain's avatar Unai Zalakain
Browse files

Fixed #7261 -- support for __html__ for library interoperability

The idea is that if an object implements __html__ which returns a string this is
used as HTML representation (eg: on escaping). If the object is a str or unicode
subclass and returns itself the object is a safe string type.

This is an updated patch based on jbalogh and ivank patches.
parent ef22d512
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -65,8 +65,8 @@ def conditional_escape(text):
    """
    Similar to escape(), except that it doesn't operate on pre-escaped strings.
    """
    if isinstance(text, SafeData):
        return text
    if hasattr(text, '__html__'):
        return text.__html__()
    else:
        return escape(text)

+7 −1
Original line number Diff line number Diff line
@@ -30,7 +30,13 @@ else:
    EscapeUnicode = EscapeText

class SafeData(object):
    pass
    def __html__(self):
        """
        Returns the html representation of a string.

        Allows interoperability with other template engines.
        """
        return self

class SafeBytes(bytes, SafeData):
    """
+7 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ from datetime import datetime
import os
from unittest import TestCase

from django.utils import html
from django.utils import html, safestring
from django.utils._os import upath
from django.utils.encoding import force_text

@@ -192,3 +192,9 @@ class TestUtilsHtml(TestCase):
        self.assertEqual(quote('http://example.com/path/öäü/'), 'http://example.com/path/%C3%B6%C3%A4%C3%BC/')
        self.assertEqual(quote('http://example.com/%C3%B6/ä/'), 'http://example.com/%C3%B6/%C3%A4/')
        self.assertEqual(quote('http://example.com/?x=1&y=2'), 'http://example.com/?x=1&y=2')

    def test_conditional_escape(self):
        s = '<h1>interop</h1>'
        self.assertEqual(html.conditional_escape(s),
                         '&lt;h1&gt;interop&lt;/h1&gt;')
        self.assertEqual(html.conditional_escape(safestring.mark_safe(s)), s)
+5 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ from django.template import Template, Context
from django.test import TestCase
from django.utils.encoding import force_text, force_bytes
from django.utils.functional import lazy, Promise
from django.utils.html import escape, conditional_escape
from django.utils.html import escape
from django.utils.safestring import mark_safe, mark_for_escaping
from django.utils import six
from django.utils import translation
@@ -50,3 +50,7 @@ class SafeStringTest(TestCase):
        s = mark_safe(translation.ugettext_lazy("username"))
        with translation.override('fr'):
            self.assertRenderEqual('{{ s }}', "nom d'utilisateur", s=s)

    def test_html(self):
        s = '<h1>interop</h1>'
        self.assertEqual(s, mark_safe(s).__html__())