def coerce2unicode(obj): """ Takes in an object and coerces every string contained in a list/dictionary/tuple key/value to unicode. Returns a copy of obj with coerced entries. Warning: this is a superficial deep copy with coercion; only tuples, lists, dicts and string types are recreated, with other references remaining intact. """ if isinstance(obj, six.string_types): return ensure_text(obj) elif isinstance(obj, tuple): return tuple(ObjectWithSchema.coerce2unicode(item) for item in obj) elif isinstance(obj, list): return [ObjectWithSchema.coerce2unicode(item) for item in obj] elif isinstance(obj, dict): # Coerce both keys and values return { ObjectWithSchema.coerce2unicode(k): ObjectWithSchema.coerce2unicode(v) for k, v in obj.items() } else: # obj is something else - return as is return obj
def text_string(obj): """ Voluptuous validator that expects text strings and coerces Python 2 string literals to unicode. """ if isinstance(obj, six.string_types): return ensure_text(obj) raise Invalid('expected str (or unicode)')
def test_ensure_text(): UNICODE_EMOJI = six.u("\U0001F600") BINARY_EMOJI = b"\xf0\x9f\x98\x80" converted_unicode = ensure_text(UNICODE_EMOJI, encoding='utf-8', errors='strict') converted_binary = ensure_text(BINARY_EMOJI, encoding="utf-8", errors='strict') if six.PY2: # PY2: unicode -> unicode assert converted_unicode == UNICODE_EMOJI and isinstance( converted_unicode, unicode) # PY2: str -> unicode assert converted_binary == UNICODE_EMOJI and isinstance( converted_unicode, unicode) else: # PY3: str -> str assert converted_unicode == UNICODE_EMOJI and isinstance( converted_unicode, str) # PY3: bytes -> str assert converted_binary == UNICODE_EMOJI and isinstance( converted_unicode, str)
def test_ensure_text_raises_error(): msg = "not expecting type '{int}'".format(int=int) with raises(TypeError, match=msg): ensure_text(5)