diff -r 000000000000 -r 0d40e90630ef web/lib/django/utils/safestring.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/django/utils/safestring.py Wed Jan 20 00:34:04 2010 +0100 @@ -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)) +