tighten up validate_value logic and allow string promotion to integers
This commit is contained in:
parent
15a239350e
commit
aedf967cf5
@ -249,7 +249,7 @@ class TestTypes(unittest.TestCase):
|
|||||||
assert value.a is types.Unset
|
assert value.a is types.Unset
|
||||||
|
|
||||||
def test_validate_dict(self):
|
def test_validate_dict(self):
|
||||||
types.validate_value({int: str}, {1: '1', 5: '5'})
|
assert types.validate_value({int: str}, {1: '1', 5: '5'})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
types.validate_value({int: str}, [])
|
types.validate_value({int: str}, [])
|
||||||
@ -257,11 +257,7 @@ class TestTypes(unittest.TestCase):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
assert types.validate_value({int: str}, {'1': '1', 5: '5'})
|
||||||
types.validate_value({int: str}, {'1': '1', 5: '5'})
|
|
||||||
assert False, "No ValueError raised"
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
types.validate_value({int: str}, {1: 1, 5: '5'})
|
types.validate_value({int: str}, {1: 1, 5: '5'})
|
||||||
@ -273,6 +269,21 @@ class TestTypes(unittest.TestCase):
|
|||||||
self.assertEqual(types.validate_value(float, 1), 1.0)
|
self.assertEqual(types.validate_value(float, 1), 1.0)
|
||||||
self.assertEqual(types.validate_value(float, '1'), 1.0)
|
self.assertEqual(types.validate_value(float, '1'), 1.0)
|
||||||
self.assertEqual(types.validate_value(float, 1.1), 1.1)
|
self.assertEqual(types.validate_value(float, 1.1), 1.1)
|
||||||
|
try:
|
||||||
|
types.validate_value(float, [])
|
||||||
|
assert False, "No ValueError raised"
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_validate_int(self):
|
||||||
|
self.assertEqual(types.validate_value(int, 1), 1)
|
||||||
|
self.assertEqual(types.validate_value(int, '1'), 1)
|
||||||
|
self.assertEqual(types.validate_value(int, six.u('1')), 1)
|
||||||
|
try:
|
||||||
|
types.validate_value(int, 1.1)
|
||||||
|
assert False, "No ValueError raised"
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
def test_register_invalid_array(self):
|
def test_register_invalid_array(self):
|
||||||
self.assertRaises(ValueError, types.register_type, [])
|
self.assertRaises(ValueError, types.register_type, [])
|
||||||
|
@ -178,6 +178,8 @@ pod_types = six.integer_types + (
|
|||||||
dt_types = (datetime.date, datetime.time, datetime.datetime)
|
dt_types = (datetime.date, datetime.time, datetime.datetime)
|
||||||
extra_types = (binary, decimal.Decimal)
|
extra_types = (binary, decimal.Decimal)
|
||||||
native_types = pod_types + dt_types + extra_types
|
native_types = pod_types + dt_types + extra_types
|
||||||
|
# The types for which we allow promotion to certain numbers.
|
||||||
|
_promotable_types = six.integer_types + (text, bytes)
|
||||||
|
|
||||||
|
|
||||||
def iscomplex(datatype):
|
def iscomplex(datatype):
|
||||||
@ -194,40 +196,49 @@ def isdict(datatype):
|
|||||||
|
|
||||||
|
|
||||||
def validate_value(datatype, value):
|
def validate_value(datatype, value):
|
||||||
|
if value in (Unset, None):
|
||||||
|
return value
|
||||||
|
|
||||||
|
# Try to promote the data type to one of our complex types.
|
||||||
|
if isinstance(datatype, list):
|
||||||
|
datatype = ArrayType(datatype[0])
|
||||||
|
elif isinstance(datatype, dict):
|
||||||
|
datatype = DictType(*list(datatype.items())[0])
|
||||||
|
|
||||||
|
# If the datatype has its own validator, use that.
|
||||||
if hasattr(datatype, 'validate'):
|
if hasattr(datatype, 'validate'):
|
||||||
return datatype.validate(value)
|
return datatype.validate(value)
|
||||||
else:
|
|
||||||
if value in (Unset, None):
|
|
||||||
return value
|
|
||||||
|
|
||||||
if isinstance(datatype, list):
|
# Do type promotion/conversion and data validation for builtin
|
||||||
datatype = ArrayType(datatype[0])
|
# types.
|
||||||
if isinstance(datatype, dict):
|
v_type = type(value)
|
||||||
datatype = DictType(*list(datatype.items())[0])
|
if datatype in six.integer_types:
|
||||||
if isarray(datatype):
|
if v_type in _promotable_types:
|
||||||
datatype.validate(value)
|
try:
|
||||||
elif isdict(datatype):
|
# Try to turn the value into an int
|
||||||
datatype.validate(value)
|
value = datatype(value)
|
||||||
elif datatype in six.integer_types:
|
except ValueError:
|
||||||
if not isinstance(value, six.integer_types):
|
# An error is raised at the end of the function
|
||||||
raise ValueError(
|
# when the types don't match.
|
||||||
"Wrong type. Expected an integer, got '%s'" % (
|
pass
|
||||||
type(value)
|
elif datatype is float and v_type in _promotable_types:
|
||||||
))
|
try:
|
||||||
elif datatype is text and isinstance(value, bytes):
|
|
||||||
value = value.decode()
|
|
||||||
elif datatype is bytes and isinstance(value, text):
|
|
||||||
value = value.encode()
|
|
||||||
elif datatype is float and (isinstance(value, int)
|
|
||||||
or isinstance(value, text)
|
|
||||||
or isinstance(value, bytes)):
|
|
||||||
value = float(value)
|
value = float(value)
|
||||||
elif not isinstance(value, datatype):
|
except ValueError:
|
||||||
raise ValueError(
|
# An error is raised at the end of the function
|
||||||
"Wrong type. Expected '%s', got '%s'" % (
|
# when the types don't match.
|
||||||
datatype, type(value)
|
pass
|
||||||
))
|
elif datatype is text and isinstance(value, bytes):
|
||||||
return value
|
value = value.decode()
|
||||||
|
elif datatype is bytes and isinstance(value, text):
|
||||||
|
value = value.encode()
|
||||||
|
|
||||||
|
if not isinstance(value, datatype):
|
||||||
|
raise ValueError(
|
||||||
|
"Wrong type. Expected '%s', got '%s'" % (
|
||||||
|
datatype, v_type
|
||||||
|
))
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class wsproperty(property):
|
class wsproperty(property):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user