Fixed #7496 -- It's now possible to pickle SortedDicts with pickle protocol 2
[django.git] / django / utils / safestring.py
blob2e31c236764b474b4ace186e2b523f903564499e
1 """
2 Functions for working with "safe strings": strings that can be displayed safely
3 without further escaping in HTML. Marking something as a "safe string" means
4 that the producer of the string has already turned characters that should not
5 be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
6 """
7 from django.utils.functional import curry, Promise
9 class EscapeData(object):
10 pass
12 class EscapeString(str, EscapeData):
13 """
14 A string that should be HTML-escaped when output.
15 """
16 pass
18 class EscapeUnicode(unicode, EscapeData):
19 """
20 A unicode object that should be HTML-escaped when output.
21 """
22 pass
24 class SafeData(object):
25 pass
27 class SafeString(str, SafeData):
28 """
29 A string subclass that has been specifically marked as "safe" (requires no
30 further escaping) for HTML output purposes.
31 """
32 def __add__(self, rhs):
33 """
34 Concatenating a safe string with another safe string or safe unicode
35 object is safe. Otherwise, the result is no longer safe.
36 """
37 t = super(SafeString, self).__add__(rhs)
38 if isinstance(rhs, SafeUnicode):
39 return SafeUnicode(t)
40 elif isinstance(rhs, SafeString):
41 return SafeString(t)
42 return t
44 def _proxy_method(self, *args, **kwargs):
45 """
46 Wrap a call to a normal unicode method up so that we return safe
47 results. The method that is being wrapped is passed in the 'method'
48 argument.
49 """
50 method = kwargs.pop('method')
51 data = method(self, *args, **kwargs)
52 if isinstance(data, str):
53 return SafeString(data)
54 else:
55 return SafeUnicode(data)
57 decode = curry(_proxy_method, method = str.decode)
59 class SafeUnicode(unicode, SafeData):
60 """
61 A unicode subclass that has been specifically marked as "safe" for HTML
62 output purposes.
63 """
64 def __add__(self, rhs):
65 """
66 Concatenating a safe unicode object with another safe string or safe
67 unicode object is safe. Otherwise, the result is no longer safe.
68 """
69 t = super(SafeUnicode, self).__add__(rhs)
70 if isinstance(rhs, SafeData):
71 return SafeUnicode(t)
72 return t
74 def _proxy_method(self, *args, **kwargs):
75 """
76 Wrap a call to a normal unicode method up so that we return safe
77 results. The method that is being wrapped is passed in the 'method'
78 argument.
79 """
80 method = kwargs.pop('method')
81 data = method(self, *args, **kwargs)
82 if isinstance(data, str):
83 return SafeString(data)
84 else:
85 return SafeUnicode(data)
87 encode = curry(_proxy_method, method = unicode.encode)
89 def mark_safe(s):
90 """
91 Explicitly mark a string as safe for (HTML) output purposes. The returned
92 object can be used everywhere a string or unicode object is appropriate.
94 Can be called multiple times on a single string.
95 """
96 if isinstance(s, SafeData):
97 return s
98 if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
99 return SafeString(s)
100 if isinstance(s, (unicode, Promise)):
101 return SafeUnicode(s)
102 return SafeString(str(s))
104 def mark_for_escaping(s):
106 Explicitly mark a string as requiring HTML escaping upon output. Has no
107 effect on SafeData subclasses.
109 Can be called multiple times on a single string (the resulting escaping is
110 only applied once).
112 if isinstance(s, (SafeData, EscapeData)):
113 return s
114 if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
115 return EscapeString(s)
116 if isinstance(s, (unicode, Promise)):
117 return EscapeUnicode(s)
118 return EscapeString(str(s))