Skip to content

Commit 98f72bf

Browse files
authored
Merge pull request #134 from dz0ny/fix/number_parsing
Fix number validator
2 parents f0cfa2d + 63f3ffb commit 98f72bf

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

openapi_core/schema/schemas/models.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
)
2121
from openapi_core.schema.schemas.util import (
2222
forcebool, format_date, format_datetime, format_byte, format_uuid,
23+
format_number,
2324
)
2425
from openapi_core.schema.schemas.validators import (
2526
TypeValidator, AttributeValidator,
@@ -51,11 +52,19 @@ class Schema(object):
5152
SchemaFormat.BYTE: Format(format_byte, TypeValidator(text_type)),
5253
}
5354

55+
NUMBER_FORMAT_CALLABLE_GETTER = {
56+
SchemaFormat.NONE: Format(format_number, TypeValidator(
57+
integer_types + (float, ), exclude=bool)),
58+
SchemaFormat.FLOAT: Format(float, TypeValidator(float)),
59+
SchemaFormat.DOUBLE: Format(float, TypeValidator(float)),
60+
}
61+
5462
TYPE_VALIDATOR_CALLABLE_GETTER = {
5563
SchemaType.ANY: lambda x: True,
5664
SchemaType.BOOLEAN: TypeValidator(bool),
5765
SchemaType.INTEGER: TypeValidator(integer_types, exclude=bool),
58-
SchemaType.NUMBER: TypeValidator(integer_types, float, exclude=bool),
66+
SchemaType.NUMBER: TypeValidator(
67+
integer_types + (float, ), exclude=bool),
5968
SchemaType.STRING: TypeValidator(
6069
text_type, date, datetime, binary_type, UUID),
6170
SchemaType.ARRAY: TypeValidator(list, tuple),
@@ -229,16 +238,33 @@ def _unmarshal_string(self, value, custom_formatters=None, strict=True):
229238
"Failed to format value {value} to format {type}: {exception}", value, self.format, exc)
230239

231240
def _unmarshal_integer(self, value, custom_formatters=None, strict=True):
232-
if strict and not isinstance(value, (integer_types, )):
241+
if strict and not isinstance(value, integer_types):
233242
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
234243

235244
return int(value)
236245

237246
def _unmarshal_number(self, value, custom_formatters=None, strict=True):
238-
if strict and not isinstance(value, (float, )):
247+
if strict and not isinstance(value, (float, ) + integer_types):
239248
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
240249

241-
return float(value)
250+
try:
251+
schema_format = SchemaFormat(self.format)
252+
except ValueError:
253+
msg = "Unsupported format {type} unmarshalling for value {value}"
254+
if custom_formatters is not None:
255+
formatnumber = custom_formatters.get(self.format)
256+
if formatnumber is None:
257+
raise InvalidSchemaValue(msg, value, self.format)
258+
else:
259+
raise InvalidSchemaValue(msg, value, self.format)
260+
else:
261+
formatnumber = self.NUMBER_FORMAT_CALLABLE_GETTER[schema_format]
262+
263+
try:
264+
return formatnumber.unmarshal(value)
265+
except ValueError as exc:
266+
raise InvalidCustomFormatSchemaValue(
267+
"Failed to format value {value} to format {type}: {exception}", value, self.format, exc)
242268

243269
def _unmarshal_boolean(self, value, custom_formatters=None, strict=True):
244270
if strict and not isinstance(value, (bool, )):

openapi_core/schema/schemas/util.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import datetime
44
from distutils.util import strtobool
55
from json import dumps
6-
from six import string_types, text_type
6+
from six import string_types, text_type, integer_types
77
import strict_rfc3339
88
from uuid import UUID
99

@@ -36,3 +36,10 @@ def format_uuid(value):
3636

3737
def format_byte(value, encoding='utf8'):
3838
return text_type(b64decode(value), encoding)
39+
40+
41+
def format_number(value):
42+
if isinstance(value, integer_types + (float, )):
43+
return value
44+
45+
return float(value)

tests/unit/schema/test_schemas.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,35 @@ def test_number_string_invalid(self):
270270
with pytest.raises(InvalidSchemaValue):
271271
schema.unmarshal(value)
272272

273-
def test_number_int_invalid(self):
273+
def test_number_int(self):
274274
schema = Schema('number')
275275
value = 1
276+
result = schema.unmarshal(value)
276277

277-
with pytest.raises(InvalidSchemaValue):
278-
schema.unmarshal(value)
278+
assert result == 1
279+
assert type(result) == int
280+
281+
def test_number_float(self):
282+
schema = Schema('number')
283+
value = 1.2
284+
result = schema.unmarshal(value)
285+
286+
assert result == 1.2
287+
assert type(result) == float
288+
289+
def test_number_format_float(self):
290+
schema = Schema('number', schema_format='float')
291+
value = 1.2
292+
result = schema.unmarshal(value)
293+
294+
assert result == 1.2
295+
296+
def test_number_format_double(self):
297+
schema = Schema('number', schema_format='double')
298+
value = 1.2
299+
result = schema.unmarshal(value)
300+
301+
assert result == 1.2
279302

280303

281304
class TestSchemaValidate(object):

0 commit comments

Comments
 (0)