Move param deserializers to separate subpackage

This commit is contained in:
Artur Maciag 2020-02-03 13:05:44 +00:00
parent 7b87cf9019
commit 58d5c26fee
12 changed files with 141 additions and 94 deletions

View file

View file

@ -0,0 +1,14 @@
import attr
from openapi_core.exceptions import OpenAPIError
@attr.s(hash=True)
class DeserializeError(OpenAPIError):
"""Deserialize operation error"""
value = attr.ib()
style = attr.ib()
def __str__(self):
return "Failed to deserialize value {value} with style {style}".format(
value=self.value, style=self.style)

View file

@ -0,0 +1,26 @@
from openapi_core.deserializing.exceptions import DeserializeError
from openapi_core.deserializing.parameters.exceptions import (
EmptyParameterValue,
)
from openapi_core.schema.parameters.enums import ParameterLocation
from openapi_core.schema.schemas.types import NoValue
class PrimitiveDeserializer(object):
def __init__(self, param, deserializer_callable):
self.param = param
self.deserializer_callable = deserializer_callable
def __call__(self, value):
if (self.param.location == ParameterLocation.QUERY and value == "" and
not self.param.allow_empty_value):
raise EmptyParameterValue(
value, self.param.style, self.param.name)
if not self.param.aslist or self.param.explode:
return value
try:
return self.deserializer_callable(value)
except (ValueError, TypeError, AttributeError) as exc:
raise DeserializeError(value, self.param.style)

View file

@ -0,0 +1,11 @@
import attr
from openapi_core.deserializing.exceptions import DeserializeError
@attr.s(hash=True)
class EmptyParameterValue(DeserializeError):
name = attr.ib()
def __str__(self):
return "Value of parameter cannot be empty: {0}".format(self.name)

View file

@ -0,0 +1,26 @@
import warnings
from openapi_core.deserializing.parameters.deserializers import (
PrimitiveDeserializer,
)
from openapi_core.schema.parameters.enums import ParameterStyle
class ParameterDeserializersFactory(object):
PARAMETER_STYLE_DESERIALIZERS = {
ParameterStyle.FORM: lambda x: x.split(','),
ParameterStyle.SIMPLE: lambda x: x.split(','),
ParameterStyle.SPACE_DELIMITED: lambda x: x.split(' '),
ParameterStyle.PIPE_DELIMITED: lambda x: x.split('|'),
}
def create(self, param):
if param.deprecated:
warnings.warn(
"{0} parameter is deprecated".format(param.name),
DeprecationWarning,
)
deserialize_callable = self.PARAMETER_STYLE_DESERIALIZERS[param.style]
return PrimitiveDeserializer(param, deserialize_callable)

View file

@ -27,21 +27,3 @@ class MissingRequiredParameter(MissingParameterError):
def __str__(self):
return "Missing required parameter: {0}".format(self.name)
@attr.s(hash=True)
class EmptyParameterValue(OpenAPIParameterError):
name = attr.ib()
def __str__(self):
return "Value of parameter cannot be empty: {0}".format(self.name)
@attr.s(hash=True)
class InvalidParameterValue(OpenAPIParameterError):
name = attr.ib()
original_exception = attr.ib()
def __str__(self):
return "Invalid parameter value for `{0}`: {1}".format(
self.name, self.original_exception)

View file

@ -5,12 +5,7 @@ import warnings
from openapi_core.schema.parameters.enums import (
ParameterLocation, ParameterStyle,
)
from openapi_core.schema.parameters.exceptions import (
MissingRequiredParameter, MissingParameter, InvalidParameterValue,
EmptyParameterValue,
)
from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.casting.schemas.exceptions import CastError
log = logging.getLogger(__name__)
@ -18,13 +13,6 @@ log = logging.getLogger(__name__)
class Parameter(object):
"""Represents an OpenAPI operation Parameter."""
PARAMETER_STYLE_DESERIALIZERS = {
ParameterStyle.FORM: lambda x: x.split(','),
ParameterStyle.SIMPLE: lambda x: x.split(','),
ParameterStyle.SPACE_DELIMITED: lambda x: x.split(' '),
ParameterStyle.PIPE_DELIMITED: lambda x: x.split('|'),
}
def __init__(
self, name, location, schema=None, required=False,
deprecated=False, allow_empty_value=False,
@ -61,29 +49,3 @@ class Parameter(object):
@property
def default_explode(self):
return self.style == ParameterStyle.FORM
def get_dererializer(self):
return self.PARAMETER_STYLE_DESERIALIZERS[self.style]
def deserialize(self, value):
if not self.aslist or self.explode:
return value
deserializer = self.get_dererializer()
return deserializer(value)
def deserialise(self, value):
if self.deprecated:
warnings.warn(
"{0} parameter is deprecated".format(self.name),
DeprecationWarning,
)
if (self.location == ParameterLocation.QUERY and value == "" and
not self.allow_empty_value):
raise EmptyParameterValue(self.name)
try:
return self.deserialize(value)
except (ValueError, AttributeError) as exc:
raise InvalidParameterValue(self.name, exc)

View file

@ -3,10 +3,12 @@ from itertools import chain
from six import iteritems
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.deserializing.exceptions import DeserializeError
from openapi_core.schema.media_types.exceptions import (
InvalidMediaTypeValue, InvalidContentType,
)
from openapi_core.schema.operations.exceptions import InvalidOperation
from openapi_core.schema.parameters.enums import ParameterLocation
from openapi_core.schema.parameters.exceptions import (
OpenAPIParameterError, MissingRequiredParameter, MissingParameter,
)
@ -110,8 +112,9 @@ class RequestValidator(object):
casted = param.schema.default
else:
try:
deserialised = self._deserialise(param, raw_value)
except OpenAPIParameterError as exc:
deserialised = self._deserialise_parameter(
param, raw_value)
except DeserializeError as exc:
errors.append(exc)
continue
@ -146,7 +149,7 @@ class RequestValidator(object):
return None, [exc, ]
try:
deserialised = self._deserialise(media_type, raw_body)
deserialised = self._deserialise_media_type(media_type, raw_body)
except InvalidMediaTypeValue as exc:
return None, [exc, ]
@ -183,9 +186,17 @@ class RequestValidator(object):
raise MissingRequestBody(request)
return request.body
def _deserialise(self, param_or_media_type, value):
def _deserialise_media_type(self, param_or_media_type, value):
return param_or_media_type.deserialise(value)
def _deserialise_parameter(self, param, value):
from openapi_core.deserializing.parameters.factories import (
ParameterDeserializersFactory,
)
deserializers_factory = ParameterDeserializersFactory()
deserializer = deserializers_factory.create(param)
return deserializer(value)
def _cast(self, param_or_media_type, value):
# return param_or_media_type.cast(value)
if not param_or_media_type.schema:

View file

@ -6,10 +6,14 @@ from uuid import UUID
from six import text_type
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.deserializing.exceptions import DeserializeError
from openapi_core.deserializing.parameters.exceptions import (
EmptyParameterValue,
)
from openapi_core.extensions.models.models import BaseModel
from openapi_core.schema.media_types.exceptions import InvalidContentType
from openapi_core.schema.parameters.exceptions import (
MissingRequiredParameter, InvalidParameterValue, EmptyParameterValue,
MissingRequiredParameter,
)
from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.schema.servers.exceptions import InvalidServer
@ -273,7 +277,7 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params,
)
with pytest.raises(InvalidParameterValue):
with pytest.raises(DeserializeError):
validate_parameters(spec, request)
body = validate_body(spec, request)

View file

@ -0,0 +1,43 @@
import pytest
from openapi_core.deserializing.parameters.factories import (
ParameterDeserializersFactory,
)
from openapi_core.deserializing.parameters.exceptions import (
EmptyParameterValue,
)
from openapi_core.schema.parameters.models import Parameter
@pytest.fixture
def deserializer_factory():
def create_deserializer(param):
return ParameterDeserializersFactory().create(param)
return create_deserializer
class TestParameterDeserialise(object):
def test_deprecated(self, deserializer_factory):
param = Parameter('param', 'query', deprecated=True)
value = 'test'
with pytest.warns(DeprecationWarning):
result = deserializer_factory(param)(value)
assert result == value
def test_query_empty(self, deserializer_factory):
param = Parameter('param', 'query')
value = ''
with pytest.raises(EmptyParameterValue):
deserializer_factory(param)(value)
def test_query_valid(self, deserializer_factory):
param = Parameter('param', 'query')
value = 'test'
result = deserializer_factory(param)(value)
assert result == value

View file

@ -1,8 +1,3 @@
import pytest
from openapi_core.schema.parameters.exceptions import (
EmptyParameterValue,
)
from openapi_core.schema.parameters.enums import ParameterStyle
from openapi_core.schema.parameters.models import Parameter
@ -36,30 +31,3 @@ class TestParameterInit(object):
assert param.allow_empty_value is False
assert param.style == ParameterStyle.FORM
assert param.explode is True
class TestParameterDeserialise(object):
def test_deprecated(self):
param = Parameter('param', 'query', deprecated=True)
value = 'test'
with pytest.warns(DeprecationWarning):
result = param.deserialise(value)
assert result == value
def test_query_empty(self):
param = Parameter('param', 'query')
value = ''
with pytest.raises(EmptyParameterValue):
param.deserialise(value)
def test_query_valid(self):
param = Parameter('param', 'query')
value = 'test'
result = param.deserialise(value)
assert result == value