app/django/utils/safestring.py
changeset 54 03e267d67478
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     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
       
     8 
       
     9 class EscapeData(object):
       
    10     pass
       
    11 
       
    12 class EscapeString(str, EscapeData):
       
    13     """
       
    14     A string that should be HTML-escaped when output.
       
    15     """
       
    16     pass
       
    17 
       
    18 class EscapeUnicode(unicode, EscapeData):
       
    19     """
       
    20     A unicode object that should be HTML-escaped when output.
       
    21     """
       
    22     pass
       
    23 
       
    24 class SafeData(object):
       
    25     pass
       
    26 
       
    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
       
    43         
       
    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)
       
    56 
       
    57     decode = curry(_proxy_method, method = str.decode)
       
    58 
       
    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
       
    73     
       
    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)
       
    86 
       
    87     encode = curry(_proxy_method, method = unicode.encode)
       
    88 
       
    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.
       
    93 
       
    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))
       
   103 
       
   104 def mark_for_escaping(s):
       
   105     """
       
   106     Explicitly mark a string as requiring HTML escaping upon output. Has no
       
   107     effect on SafeData subclasses.
       
   108 
       
   109     Can be called multiple times on a single string (the resulting escaping is
       
   110     only applied once).
       
   111     """
       
   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))
       
   119