Merge pull request #79 from grktsh/string-format

Support unmarshaling string with format keyword
This commit is contained in:
A 2018-08-17 11:25:59 +01:00 committed by GitHub
commit 06e80079fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 3 deletions

View file

@ -6,12 +6,12 @@ import warnings
from six import iteritems
from openapi_core.extensions.models.factories import ModelFactory
from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType
from openapi_core.schema.schemas.exceptions import (
InvalidSchemaValue, UndefinedSchemaProperty, MissingSchemaProperty,
OpenAPISchemaError, NoOneOfSchema, MultipleOneOfSchema,
)
from openapi_core.schema.schemas.util import forcebool
from openapi_core.schema.schemas.util import forcebool, format_date
log = logging.getLogger(__name__)
@ -25,6 +25,10 @@ class Schema(object):
SchemaType.BOOLEAN: forcebool,
}
FORMAT_CALLABLE_GETTER = defaultdict(lambda: lambda x: x, {
SchemaFormat.DATE.value: format_date,
})
def __init__(
self, schema_type=None, model=None, properties=None, items=None,
schema_format=None, required=None, default=None, nullable=False,
@ -92,6 +96,7 @@ class Schema(object):
def get_cast_mapping(self):
mapping = self.DEFAULT_CAST_CALLABLE_GETTER.copy()
mapping.update({
SchemaType.STRING: self._unmarshal_string,
SchemaType.ARRAY: self._unmarshal_collection,
SchemaType.OBJECT: self._unmarshal_object,
})
@ -110,7 +115,7 @@ class Schema(object):
cast_mapping = self.get_cast_mapping()
if self.type in cast_mapping and value == '':
if self.type is not SchemaType.STRING and value == '':
return None
cast_callable = cast_mapping[self.type]
@ -139,6 +144,16 @@ class Schema(object):
return casted
def _unmarshal_string(self, value):
formatter = self.FORMAT_CALLABLE_GETTER[self.format]
try:
return formatter(value)
except ValueError:
raise InvalidSchemaValue(
"Failed to format value of {0} to {1}".format(
value, self.format)
)
def _unmarshal_collection(self, value):
return list(map(self.items.unmarshal, value))

View file

@ -1,4 +1,5 @@
"""OpenAPI core schemas util module"""
import datetime
from distutils.util import strtobool
from json import dumps
from six import string_types
@ -13,3 +14,7 @@ def forcebool(val):
def dicthash(d):
return hash(dumps(d, sort_keys=True))
def format_date(value):
return datetime.datetime.strptime(value, '%Y-%m-%d').date()

View file

@ -1,3 +1,5 @@
import datetime
import mock
import pytest
@ -64,6 +66,49 @@ class TestSchemaUnmarshal(object):
assert result == default_value
def test_string_format_date(self):
schema = Schema('string', schema_format='date')
value = '2018-01-02'
result = schema.unmarshal(value)
assert result == datetime.date(2018, 1, 2)
def test_string_format_custom(self):
custom_format = 'custom'
schema = Schema('string', schema_format=custom_format)
value = 'x'
with mock.patch.dict(
Schema.FORMAT_CALLABLE_GETTER,
{custom_format: lambda x: x + '-custom'},
):
result = schema.unmarshal(value)
assert result == 'x-custom'
def test_string_format_unknown(self):
unknown_format = 'unknown'
schema = Schema('string', schema_format=unknown_format)
value = 'x'
result = schema.unmarshal(value)
assert result == 'x'
def test_string_format_invalid_value(self):
custom_format = 'custom'
schema = Schema('string', schema_format=custom_format)
value = 'x'
with mock.patch.dict(
Schema.FORMAT_CALLABLE_GETTER,
{custom_format: mock.Mock(side_effect=ValueError())},
), pytest.raises(
InvalidSchemaValue, message='Failed to format value'
):
schema.unmarshal(value)
def test_integer_valid(self):
schema = Schema('integer')
value = '123'