You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
2.2 KiB

  1. import datetime
  2. from decimal import Decimal
  3. import types
  4. import six
  5. def is_protected_type(obj):
  6. """Determine if the object instance is of a protected type.
  7. Objects of protected types are preserved as-is when passed to
  8. force_unicode(strings_only=True).
  9. """
  10. return isinstance(obj, (
  11. six.integer_types +
  12. (types.NoneType,
  13. datetime.datetime, datetime.date, datetime.time,
  14. float, Decimal))
  15. )
  16. def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
  17. """
  18. Similar to smart_text, except that lazy instances are resolved to
  19. strings, rather than kept as lazy objects.
  20. If strings_only is True, don't convert (some) non-string-like objects.
  21. """
  22. # Handle the common case first, saves 30-40% when s is an instance of
  23. # six.text_type. This function gets called often in that setting.
  24. if isinstance(s, six.text_type):
  25. return s
  26. if strings_only and is_protected_type(s):
  27. return s
  28. try:
  29. if not isinstance(s, six.string_types):
  30. if hasattr(s, '__unicode__'):
  31. s = s.__unicode__()
  32. else:
  33. if six.PY3:
  34. if isinstance(s, bytes):
  35. s = six.text_type(s, encoding, errors)
  36. else:
  37. s = six.text_type(s)
  38. else:
  39. s = six.text_type(bytes(s), encoding, errors)
  40. else:
  41. # Note: We use .decode() here, instead of six.text_type(s,
  42. # encoding, errors), so that if s is a SafeBytes, it ends up being
  43. # a SafeText at the end.
  44. s = s.decode(encoding, errors)
  45. except UnicodeDecodeError as e:
  46. if not isinstance(s, Exception):
  47. raise UnicodeDecodeError(*e.args)
  48. else:
  49. # If we get to here, the caller has passed in an Exception
  50. # subclass populated with non-ASCII bytestring data without a
  51. # working unicode method. Try to handle this without raising a
  52. # further exception by individually forcing the exception args
  53. # to unicode.
  54. s = ' '.join([force_unicode(arg, encoding, strings_only,
  55. errors) for arg in s])
  56. return s