Fixed #10107 -- Allowed using mark_safe() as a decorator.
Thanks ArcTanSusan for the initial patch.
This commit is contained in:
parent
5e3f4c2e53
commit
be729b6120
|
@ -8,7 +8,7 @@ import warnings
|
||||||
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.functional import Promise, curry
|
from django.utils.functional import Promise, curry, wraps
|
||||||
|
|
||||||
|
|
||||||
class EscapeData(object):
|
class EscapeData(object):
|
||||||
|
@ -117,11 +117,20 @@ else:
|
||||||
SafeUnicode = SafeText
|
SafeUnicode = SafeText
|
||||||
|
|
||||||
|
|
||||||
|
def _safety_decorator(safety_marker, func):
|
||||||
|
@wraps(func)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
return safety_marker(func(*args, **kwargs))
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
def mark_safe(s):
|
def mark_safe(s):
|
||||||
"""
|
"""
|
||||||
Explicitly mark a string as safe for (HTML) output purposes. The returned
|
Explicitly mark a string as safe for (HTML) output purposes. The returned
|
||||||
object can be used everywhere a string or unicode object is appropriate.
|
object can be used everywhere a string or unicode object is appropriate.
|
||||||
|
|
||||||
|
If used on a method as a decorator, mark the returned data as safe.
|
||||||
|
|
||||||
Can be called multiple times on a single string.
|
Can be called multiple times on a single string.
|
||||||
"""
|
"""
|
||||||
if hasattr(s, '__html__'):
|
if hasattr(s, '__html__'):
|
||||||
|
@ -130,6 +139,8 @@ def mark_safe(s):
|
||||||
return SafeBytes(s)
|
return SafeBytes(s)
|
||||||
if isinstance(s, (six.text_type, Promise)):
|
if isinstance(s, (six.text_type, Promise)):
|
||||||
return SafeText(s)
|
return SafeText(s)
|
||||||
|
if callable(s):
|
||||||
|
return _safety_decorator(mark_safe, s)
|
||||||
return SafeString(str(s))
|
return SafeString(str(s))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -832,6 +832,8 @@ appropriate entities.
|
||||||
|
|
||||||
Can be called multiple times on a single string.
|
Can be called multiple times on a single string.
|
||||||
|
|
||||||
|
Can also be used as a decorator.
|
||||||
|
|
||||||
For building up fragments of HTML, you should normally be using
|
For building up fragments of HTML, you should normally be using
|
||||||
:func:`django.utils.html.format_html` instead.
|
:func:`django.utils.html.format_html` instead.
|
||||||
|
|
||||||
|
@ -846,6 +848,10 @@ appropriate entities.
|
||||||
>>> type(mystr)
|
>>> type(mystr)
|
||||||
<type 'str'>
|
<type 'str'>
|
||||||
|
|
||||||
|
.. versionchanged:: 1.11
|
||||||
|
|
||||||
|
Added support for decorator usage.
|
||||||
|
|
||||||
.. function:: mark_for_escaping(s)
|
.. function:: mark_for_escaping(s)
|
||||||
|
|
||||||
.. deprecated:: 1.10
|
.. deprecated:: 1.10
|
||||||
|
|
|
@ -202,7 +202,7 @@ Signals
|
||||||
Templates
|
Templates
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* :meth:`~django.utils.safestring.mark_safe` can now be used as a decorator.
|
||||||
|
|
||||||
Tests
|
Tests
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
|
@ -13,6 +13,7 @@ from django.utils.decorators import method_decorator
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.functional import allow_lazy, keep_lazy, keep_lazy_text, lazy
|
from django.utils.functional import allow_lazy, keep_lazy, keep_lazy_text, lazy
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy
|
from django.utils.translation import ugettext_lazy
|
||||||
from django.views.decorators.cache import (
|
from django.views.decorators.cache import (
|
||||||
cache_control, cache_page, never_cache,
|
cache_control, cache_page, never_cache,
|
||||||
|
@ -74,6 +75,9 @@ full_decorator = compose(
|
||||||
keep_lazy(HttpResponse),
|
keep_lazy(HttpResponse),
|
||||||
keep_lazy_text,
|
keep_lazy_text,
|
||||||
lazy,
|
lazy,
|
||||||
|
|
||||||
|
# django.utils.safestring
|
||||||
|
mark_safe,
|
||||||
)
|
)
|
||||||
|
|
||||||
fully_decorated = full_decorator(fully_decorated)
|
fully_decorated = full_decorator(fully_decorated)
|
||||||
|
|
|
@ -109,3 +109,33 @@ class SafeStringTest(SimpleTestCase):
|
||||||
s = text.slugify(lazystr('a'))
|
s = text.slugify(lazystr('a'))
|
||||||
s += mark_safe('&b')
|
s += mark_safe('&b')
|
||||||
self.assertRenderEqual('{{ s }}', 'a&b', s=s)
|
self.assertRenderEqual('{{ s }}', 'a&b', s=s)
|
||||||
|
|
||||||
|
def test_mark_safe_as_decorator(self):
|
||||||
|
"""
|
||||||
|
mark_safe used as a decorator leaves the result of a function
|
||||||
|
unchanged.
|
||||||
|
"""
|
||||||
|
def clean_string_provider():
|
||||||
|
return '<html><body>dummy</body></html>'
|
||||||
|
|
||||||
|
self.assertEqual(mark_safe(clean_string_provider)(), clean_string_provider())
|
||||||
|
|
||||||
|
def test_mark_safe_decorator_does_not_affect_dunder_html(self):
|
||||||
|
"""
|
||||||
|
mark_safe doesn't affect a callable that has an __html__() method.
|
||||||
|
"""
|
||||||
|
class SafeStringContainer:
|
||||||
|
def __html__(self):
|
||||||
|
return '<html></html>'
|
||||||
|
|
||||||
|
self.assertIs(mark_safe(SafeStringContainer), SafeStringContainer)
|
||||||
|
|
||||||
|
def test_mark_safe_decorator_does_not_affect_promises(self):
|
||||||
|
"""
|
||||||
|
mark_safe doesn't affect lazy strings (Promise objects).
|
||||||
|
"""
|
||||||
|
def html_str():
|
||||||
|
return '<html></html>'
|
||||||
|
|
||||||
|
lazy_str = lazy(html_str, str)()
|
||||||
|
self.assertEqual(mark_safe(lazy_str), html_str())
|
||||||
|
|
Loading…
Reference in New Issue