Code

Ticket #10107: patch.2.diff

File patch.2.diff, 5.0 KB (added by matehat, 5 years ago)
Line 
1Index: django/utils/safestring.py
2===================================================================
3--- django/utils/safestring.py  (revision 9781)
4+++ django/utils/safestring.py  (working copy)
5@@ -4,7 +4,7 @@
6 that the producer of the string has already turned characters that should not
7 be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
8 """
9-from django.utils.functional import curry, Promise
10+from django.utils.functional import curry, wraps, Promise
11 
12 class EscapeData(object):
13     pass
14@@ -86,13 +86,24 @@
15 
16     encode = curry(_proxy_method, method = unicode.encode)
17 
18-def mark_safe(s):
19+def _safety_decorator(safety_marker, func):
20+  @wraps(func)
21+  def wrapped(*args, **kwargs):
22+    return safety_marker(func(*args, **kwargs))
23+  return wrapped
24+
25+
26+def mark_safe(s=None):
27     """
28     Explicitly mark a string as safe for (HTML) output purposes. The returned
29     object can be used everywhere a string or unicode object is appropriate.
30 
31     Can be called multiple times on a single string.
32     """
33+    if s is None: # Used like: @mark_safe()
34+        return curry(_safety_decorator, mark_safe)
35+    if callable(s): # Used like: @mark_safe
36+        return _safety_decorator(mark_safe, s)
37     if isinstance(s, SafeData):
38         return s
39     if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
40@@ -101,7 +112,7 @@
41         return SafeUnicode(s)
42     return SafeString(str(s))
43 
44-def mark_for_escaping(s):
45+def mark_for_escaping(s=None):
46     """
47     Explicitly mark a string as requiring HTML escaping upon output. Has no
48     effect on SafeData subclasses.
49@@ -109,6 +120,11 @@
50     Can be called multiple times on a single string (the resulting escaping is
51     only applied once).
52     """
53+   
54+    if s is None:
55+        return curry(_safety_decorator, mark_for_escaping)
56+    if callable(s):
57+        return _safety_decorator(mark_for_escaping, s)
58     if isinstance(s, (SafeData, EscapeData)):
59         return s
60     if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
61Index: tests/regressiontests/decorators/tests.py
62===================================================================
63--- tests/regressiontests/decorators/tests.py   (revision 9781)
64+++ tests/regressiontests/decorators/tests.py   (working copy)
65@@ -3,6 +3,7 @@
66
67from django.http import HttpResponse
68from django.utils.functional import allow_lazy, lazy, memoize
69+from django.utils.safestring import mark_safe, mark_for_escaping
70from django.views.decorators.http import require_http_methods, require_GET, require_POST
71from django.views.decorators.vary import vary_on_headers, vary_on_cookie
72from django.views.decorators.cache import cache_page, never_cache, cache_control
73@@ -14,6 +15,7 @@
74    return HttpResponse('<html><body>dummy</body></html>')
75fully_decorated.anything = "Expected __dict__"
76
77+
78# django.views.decorators.http
79fully_decorated = require_http_methods(["GET"])(fully_decorated)
80fully_decorated = require_GET(fully_decorated)
81@@ -41,8 +43,11 @@
82fully_decorated = allow_lazy(fully_decorated)
83fully_decorated = lazy(fully_decorated)
84
85+# django.utils.safestring
86+fully_decorated = mark_safe(fully_decorated)
87+fully_decorated = mark_for_escaping(fully_decorated)
88+
89class DecoratorsTest(TestCase):
90-
91    def test_attributes(self):
92        """
93        Tests that django decorators set certain attributes of the wrapped
94@@ -54,3 +59,37 @@
95            self.assertEquals(fully_decorated.__name__, 'fully_decorated')
96        self.assertEquals(fully_decorated.__doc__, 'Expected __doc__')
97        self.assertEquals(fully_decorated.__dict__['anything'], 'Expected __dict__')
98+
99+    def test_escaping(self):
100+        """
101+        Tests that safety markers from django.utils.safestring
102+        return the proper str or unicode subclass for use in templates.
103+       
104+        Tests are done by comparing directly a sample rendered Template instance
105+        with the unicode content it should contain.
106+        """
107+        from django.template import Template, Context
108+        template = Template("{{ data }}")
109+
110+        rendered = { 'safe': u'<html><body>dummy</body></html>',
111+          'escaped': u'&lt;html&gt;&lt;body&gt;dummy&lt;/body&gt;&lt;/html&gt;' }
112+        def clean_unicode_provider():
113+            return u'<html><body>dummy</body></html>'
114+
115+        def clean_string_provider():
116+            return '<html><body>dummy</body></html>'
117+
118+        escaped_unicode = mark_for_escaping(clean_unicode_provider)()
119+        safe_unicode = mark_safe(clean_unicode_provider)()
120+        escaped_str = mark_for_escaping(clean_string_provider)()
121+        safe_str = mark_safe(clean_string_provider)()
122+
123+        self.assertEquals(template.render(Context({'data': escaped_unicode})),
124+            rendered['escaped'])
125+        self.assertEquals(template.render(Context({'data': safe_unicode})),
126+            rendered['safe'])
127+        self.assertEquals(template.render(Context({'data': escaped_str})),
128+            rendered['escaped'])
129+        self.assertEquals(template.render(Context({'data': safe_str})),
130+            rendered['safe'])
131+