app/django/utils/safestring.py
changeset 54 03e267d67478
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/utils/safestring.py	Fri Jul 18 18:22:23 2008 +0000
@@ -0,0 +1,119 @@
+"""
+Functions for working with "safe strings": strings that can be displayed safely
+without further escaping in HTML. Marking something as a "safe string" means
+that the producer of the string has already turned characters that should not
+be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
+"""
+from django.utils.functional import curry, Promise
+
+class EscapeData(object):
+    pass
+
+class EscapeString(str, EscapeData):
+    """
+    A string that should be HTML-escaped when output.
+    """
+    pass
+
+class EscapeUnicode(unicode, EscapeData):
+    """
+    A unicode object that should be HTML-escaped when output.
+    """
+    pass
+
+class SafeData(object):
+    pass
+
+class SafeString(str, SafeData):
+    """
+    A string subclass that has been specifically marked as "safe" (requires no
+    further escaping) for HTML output purposes.
+    """
+    def __add__(self, rhs):
+        """
+        Concatenating a safe string with another safe string or safe unicode
+        object is safe. Otherwise, the result is no longer safe.
+        """
+        t = super(SafeString, self).__add__(rhs)
+        if isinstance(rhs, SafeUnicode):
+            return SafeUnicode(t)
+        elif isinstance(rhs, SafeString):
+            return SafeString(t)
+        return t
+        
+    def _proxy_method(self, *args, **kwargs):
+        """
+        Wrap a call to a normal unicode method up so that we return safe
+        results. The method that is being wrapped is passed in the 'method'
+        argument.
+        """
+        method = kwargs.pop('method')
+        data = method(self, *args, **kwargs)
+        if isinstance(data, str):
+            return SafeString(data)
+        else:
+            return SafeUnicode(data)
+
+    decode = curry(_proxy_method, method = str.decode)
+
+class SafeUnicode(unicode, SafeData):
+    """
+    A unicode subclass that has been specifically marked as "safe" for HTML
+    output purposes.
+    """
+    def __add__(self, rhs):
+        """
+        Concatenating a safe unicode object with another safe string or safe
+        unicode object is safe. Otherwise, the result is no longer safe.
+        """
+        t = super(SafeUnicode, self).__add__(rhs)
+        if isinstance(rhs, SafeData):
+            return SafeUnicode(t)
+        return t
+    
+    def _proxy_method(self, *args, **kwargs):
+        """
+        Wrap a call to a normal unicode method up so that we return safe
+        results. The method that is being wrapped is passed in the 'method'
+        argument.
+        """
+        method = kwargs.pop('method')
+        data = method(self, *args, **kwargs)
+        if isinstance(data, str):
+            return SafeString(data)
+        else:
+            return SafeUnicode(data)
+
+    encode = curry(_proxy_method, method = unicode.encode)
+
+def mark_safe(s):
+    """
+    Explicitly mark a string as safe for (HTML) output purposes. The returned
+    object can be used everywhere a string or unicode object is appropriate.
+
+    Can be called multiple times on a single string.
+    """
+    if isinstance(s, SafeData):
+        return s
+    if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
+        return SafeString(s)
+    if isinstance(s, (unicode, Promise)):
+        return SafeUnicode(s)
+    return SafeString(str(s))
+
+def mark_for_escaping(s):
+    """
+    Explicitly mark a string as requiring HTML escaping upon output. Has no
+    effect on SafeData subclasses.
+
+    Can be called multiple times on a single string (the resulting escaping is
+    only applied once).
+    """
+    if isinstance(s, (SafeData, EscapeData)):
+        return s
+    if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
+        return EscapeString(s)
+    if isinstance(s, (unicode, Promise)):
+        return EscapeUnicode(s)
+    return EscapeString(str(s))
+