diff --git a/django/utils/encoding.py b/django/utils/encoding.py index c54e67610f..dbd2c7a211 100644 --- a/django/utils/encoding.py +++ b/django/utils/encoding.py @@ -48,7 +48,19 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): if hasattr(s, '__unicode__'): s = unicode(s) else: - s = unicode(str(s), encoding, errors) + try: + s = unicode(str(s), encoding, errors) + except UnicodeEncodeError: + if not isinstance(s, Exception): + raise + # If we get to here, the caller has passed in an Exception + # subclass populated with non-ASCII data without special + # handling to display as a string. We need to handle this + # without raising a further exception. We do an + # approximation to what the Exception's standard str() + # output should be. + s = ' '.join([force_unicode(arg, encoding, strings_only, + errors) for arg in s]) elif not isinstance(s, unicode): # Note: We use .decode() here, instead of unicode(s, encoding, # errors), so that if s is a SafeString, it ends up being a @@ -72,6 +84,12 @@ def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): try: return str(s) except UnicodeEncodeError: + if isinstance(s, Exception): + # An Exception subclass containing non-ASCII data that doesn't + # know how to print itself properly. We shouldn't raise a + # further exception. + return ' '.join([smart_str(arg, encoding, strings_only, + errors) for arg in s]) return unicode(s).encode(encoding, errors) elif isinstance(s, unicode): return s.encode(encoding, errors)