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.
7 from django
.utils
.functional
import curry
, Promise
9 class EscapeData(object):
12 class EscapeString(str, EscapeData
):
14 A string that should be HTML-escaped when output.
18 class EscapeUnicode(unicode, EscapeData
):
20 A unicode object that should be HTML-escaped when output.
24 class SafeData(object):
27 class SafeString(str, SafeData
):
29 A string subclass that has been specifically marked as "safe" (requires no
30 further escaping) for HTML output purposes.
32 def __add__(self
, rhs
):
34 Concatenating a safe string with another safe string or safe unicode
35 object is safe. Otherwise, the result is no longer safe.
37 t
= super(SafeString
, self
).__add
__(rhs
)
38 if isinstance(rhs
, SafeUnicode
):
40 elif isinstance(rhs
, SafeString
):
44 def _proxy_method(self
, *args
, **kwargs
):
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'
50 method
= kwargs
.pop('method')
51 data
= method(self
, *args
, **kwargs
)
52 if isinstance(data
, str):
53 return SafeString(data
)
55 return SafeUnicode(data
)
57 decode
= curry(_proxy_method
, method
= str.decode
)
59 class SafeUnicode(unicode, SafeData
):
61 A unicode subclass that has been specifically marked as "safe" for HTML
64 def __add__(self
, rhs
):
66 Concatenating a safe unicode object with another safe string or safe
67 unicode object is safe. Otherwise, the result is no longer safe.
69 t
= super(SafeUnicode
, self
).__add
__(rhs
)
70 if isinstance(rhs
, SafeData
):
74 def _proxy_method(self
, *args
, **kwargs
):
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'
80 method
= kwargs
.pop('method')
81 data
= method(self
, *args
, **kwargs
)
82 if isinstance(data
, str):
83 return SafeString(data
)
85 return SafeUnicode(data
)
87 encode
= curry(_proxy_method
, method
= unicode.encode
)
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.
96 if isinstance(s
, SafeData
):
98 if isinstance(s
, str) or (isinstance(s
, Promise
) and s
._delegate
_str
):
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
112 if isinstance(s
, (SafeData
, EscapeData
)):
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
))