Skip to content

Commit 58d5c26

Browse files
committed
Move param deserializers to separate subpackage
1 parent 7b87cf9 commit 58d5c26

File tree

12 files changed

+141
-94
lines changed

12 files changed

+141
-94
lines changed

openapi_core/deserializing/__init__.py

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import attr
2+
3+
from openapi_core.exceptions import OpenAPIError
4+
5+
6+
@attr.s(hash=True)
7+
class DeserializeError(OpenAPIError):
8+
"""Deserialize operation error"""
9+
value = attr.ib()
10+
style = attr.ib()
11+
12+
def __str__(self):
13+
return "Failed to deserialize value {value} with style {style}".format(
14+
value=self.value, style=self.style)

openapi_core/deserializing/parameters/__init__.py

Whitespace-only changes.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from openapi_core.deserializing.exceptions import DeserializeError
2+
from openapi_core.deserializing.parameters.exceptions import (
3+
EmptyParameterValue,
4+
)
5+
from openapi_core.schema.parameters.enums import ParameterLocation
6+
from openapi_core.schema.schemas.types import NoValue
7+
8+
9+
class PrimitiveDeserializer(object):
10+
11+
def __init__(self, param, deserializer_callable):
12+
self.param = param
13+
self.deserializer_callable = deserializer_callable
14+
15+
def __call__(self, value):
16+
if (self.param.location == ParameterLocation.QUERY and value == "" and
17+
not self.param.allow_empty_value):
18+
raise EmptyParameterValue(
19+
value, self.param.style, self.param.name)
20+
21+
if not self.param.aslist or self.param.explode:
22+
return value
23+
try:
24+
return self.deserializer_callable(value)
25+
except (ValueError, TypeError, AttributeError) as exc:
26+
raise DeserializeError(value, self.param.style)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import attr
2+
3+
from openapi_core.deserializing.exceptions import DeserializeError
4+
5+
6+
@attr.s(hash=True)
7+
class EmptyParameterValue(DeserializeError):
8+
name = attr.ib()
9+
10+
def __str__(self):
11+
return "Value of parameter cannot be empty: {0}".format(self.name)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import warnings
2+
3+
from openapi_core.deserializing.parameters.deserializers import (
4+
PrimitiveDeserializer,
5+
)
6+
from openapi_core.schema.parameters.enums import ParameterStyle
7+
8+
9+
class ParameterDeserializersFactory(object):
10+
11+
PARAMETER_STYLE_DESERIALIZERS = {
12+
ParameterStyle.FORM: lambda x: x.split(','),
13+
ParameterStyle.SIMPLE: lambda x: x.split(','),
14+
ParameterStyle.SPACE_DELIMITED: lambda x: x.split(' '),
15+
ParameterStyle.PIPE_DELIMITED: lambda x: x.split('|'),
16+
}
17+
18+
def create(self, param):
19+
if param.deprecated:
20+
warnings.warn(
21+
"{0} parameter is deprecated".format(param.name),
22+
DeprecationWarning,
23+
)
24+
25+
deserialize_callable = self.PARAMETER_STYLE_DESERIALIZERS[param.style]
26+
return PrimitiveDeserializer(param, deserialize_callable)

openapi_core/schema/parameters/exceptions.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,3 @@ class MissingRequiredParameter(MissingParameterError):
2727

2828
def __str__(self):
2929
return "Missing required parameter: {0}".format(self.name)
30-
31-
32-
@attr.s(hash=True)
33-
class EmptyParameterValue(OpenAPIParameterError):
34-
name = attr.ib()
35-
36-
def __str__(self):
37-
return "Value of parameter cannot be empty: {0}".format(self.name)
38-
39-
40-
@attr.s(hash=True)
41-
class InvalidParameterValue(OpenAPIParameterError):
42-
name = attr.ib()
43-
original_exception = attr.ib()
44-
45-
def __str__(self):
46-
return "Invalid parameter value for `{0}`: {1}".format(
47-
self.name, self.original_exception)

openapi_core/schema/parameters/models.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,14 @@
55
from openapi_core.schema.parameters.enums import (
66
ParameterLocation, ParameterStyle,
77
)
8-
from openapi_core.schema.parameters.exceptions import (
9-
MissingRequiredParameter, MissingParameter, InvalidParameterValue,
10-
EmptyParameterValue,
11-
)
128
from openapi_core.schema.schemas.enums import SchemaType
13-
from openapi_core.casting.schemas.exceptions import CastError
149

1510
log = logging.getLogger(__name__)
1611

1712

1813
class Parameter(object):
1914
"""Represents an OpenAPI operation Parameter."""
2015

21-
PARAMETER_STYLE_DESERIALIZERS = {
22-
ParameterStyle.FORM: lambda x: x.split(','),
23-
ParameterStyle.SIMPLE: lambda x: x.split(','),
24-
ParameterStyle.SPACE_DELIMITED: lambda x: x.split(' '),
25-
ParameterStyle.PIPE_DELIMITED: lambda x: x.split('|'),
26-
}
27-
2816
def __init__(
2917
self, name, location, schema=None, required=False,
3018
deprecated=False, allow_empty_value=False,
@@ -61,29 +49,3 @@ def default_style(self):
6149
@property
6250
def default_explode(self):
6351
return self.style == ParameterStyle.FORM
64-
65-
def get_dererializer(self):
66-
return self.PARAMETER_STYLE_DESERIALIZERS[self.style]
67-
68-
def deserialize(self, value):
69-
if not self.aslist or self.explode:
70-
return value
71-
72-
deserializer = self.get_dererializer()
73-
return deserializer(value)
74-
75-
def deserialise(self, value):
76-
if self.deprecated:
77-
warnings.warn(
78-
"{0} parameter is deprecated".format(self.name),
79-
DeprecationWarning,
80-
)
81-
82-
if (self.location == ParameterLocation.QUERY and value == "" and
83-
not self.allow_empty_value):
84-
raise EmptyParameterValue(self.name)
85-
86-
try:
87-
return self.deserialize(value)
88-
except (ValueError, AttributeError) as exc:
89-
raise InvalidParameterValue(self.name, exc)

openapi_core/validation/request/validators.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
from six import iteritems
44

55
from openapi_core.casting.schemas.exceptions import CastError
6+
from openapi_core.deserializing.exceptions import DeserializeError
67
from openapi_core.schema.media_types.exceptions import (
78
InvalidMediaTypeValue, InvalidContentType,
89
)
910
from openapi_core.schema.operations.exceptions import InvalidOperation
11+
from openapi_core.schema.parameters.enums import ParameterLocation
1012
from openapi_core.schema.parameters.exceptions import (
1113
OpenAPIParameterError, MissingRequiredParameter, MissingParameter,
1214
)
@@ -110,8 +112,9 @@ def _get_parameters(self, request, params):
110112
casted = param.schema.default
111113
else:
112114
try:
113-
deserialised = self._deserialise(param, raw_value)
114-
except OpenAPIParameterError as exc:
115+
deserialised = self._deserialise_parameter(
116+
param, raw_value)
117+
except DeserializeError as exc:
115118
errors.append(exc)
116119
continue
117120

@@ -146,7 +149,7 @@ def _get_body(self, request, operation):
146149
return None, [exc, ]
147150

148151
try:
149-
deserialised = self._deserialise(media_type, raw_body)
152+
deserialised = self._deserialise_media_type(media_type, raw_body)
150153
except InvalidMediaTypeValue as exc:
151154
return None, [exc, ]
152155

@@ -183,9 +186,17 @@ def _get_body_value(self, request_body, request):
183186
raise MissingRequestBody(request)
184187
return request.body
185188

186-
def _deserialise(self, param_or_media_type, value):
189+
def _deserialise_media_type(self, param_or_media_type, value):
187190
return param_or_media_type.deserialise(value)
188191

192+
def _deserialise_parameter(self, param, value):
193+
from openapi_core.deserializing.parameters.factories import (
194+
ParameterDeserializersFactory,
195+
)
196+
deserializers_factory = ParameterDeserializersFactory()
197+
deserializer = deserializers_factory.create(param)
198+
return deserializer(value)
199+
189200
def _cast(self, param_or_media_type, value):
190201
# return param_or_media_type.cast(value)
191202
if not param_or_media_type.schema:

tests/integration/validation/test_petstore.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
from six import text_type
77

88
from openapi_core.casting.schemas.exceptions import CastError
9+
from openapi_core.deserializing.exceptions import DeserializeError
10+
from openapi_core.deserializing.parameters.exceptions import (
11+
EmptyParameterValue,
12+
)
913
from openapi_core.extensions.models.models import BaseModel
1014
from openapi_core.schema.media_types.exceptions import InvalidContentType
1115
from openapi_core.schema.parameters.exceptions import (
12-
MissingRequiredParameter, InvalidParameterValue, EmptyParameterValue,
16+
MissingRequiredParameter,
1317
)
1418
from openapi_core.schema.schemas.enums import SchemaType
1519
from openapi_core.schema.servers.exceptions import InvalidServer
@@ -273,7 +277,7 @@ def test_get_pets_parameter_deserialization_error(self, spec):
273277
path_pattern=path_pattern, args=query_params,
274278
)
275279

276-
with pytest.raises(InvalidParameterValue):
280+
with pytest.raises(DeserializeError):
277281
validate_parameters(spec, request)
278282

279283
body = validate_body(spec, request)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import pytest
2+
3+
from openapi_core.deserializing.parameters.factories import (
4+
ParameterDeserializersFactory,
5+
)
6+
from openapi_core.deserializing.parameters.exceptions import (
7+
EmptyParameterValue,
8+
)
9+
from openapi_core.schema.parameters.models import Parameter
10+
11+
12+
@pytest.fixture
13+
def deserializer_factory():
14+
def create_deserializer(param):
15+
return ParameterDeserializersFactory().create(param)
16+
return create_deserializer
17+
18+
19+
class TestParameterDeserialise(object):
20+
21+
def test_deprecated(self, deserializer_factory):
22+
param = Parameter('param', 'query', deprecated=True)
23+
value = 'test'
24+
25+
with pytest.warns(DeprecationWarning):
26+
result = deserializer_factory(param)(value)
27+
28+
assert result == value
29+
30+
def test_query_empty(self, deserializer_factory):
31+
param = Parameter('param', 'query')
32+
value = ''
33+
34+
with pytest.raises(EmptyParameterValue):
35+
deserializer_factory(param)(value)
36+
37+
def test_query_valid(self, deserializer_factory):
38+
param = Parameter('param', 'query')
39+
value = 'test'
40+
41+
result = deserializer_factory(param)(value)
42+
43+
assert result == value

tests/unit/schema/test_parameters.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
import pytest
2-
3-
from openapi_core.schema.parameters.exceptions import (
4-
EmptyParameterValue,
5-
)
61
from openapi_core.schema.parameters.enums import ParameterStyle
72
from openapi_core.schema.parameters.models import Parameter
83

@@ -36,30 +31,3 @@ def test_cookie(self):
3631
assert param.allow_empty_value is False
3732
assert param.style == ParameterStyle.FORM
3833
assert param.explode is True
39-
40-
41-
class TestParameterDeserialise(object):
42-
43-
def test_deprecated(self):
44-
param = Parameter('param', 'query', deprecated=True)
45-
value = 'test'
46-
47-
with pytest.warns(DeprecationWarning):
48-
result = param.deserialise(value)
49-
50-
assert result == value
51-
52-
def test_query_empty(self):
53-
param = Parameter('param', 'query')
54-
value = ''
55-
56-
with pytest.raises(EmptyParameterValue):
57-
param.deserialise(value)
58-
59-
def test_query_valid(self):
60-
param = Parameter('param', 'query')
61-
value = 'test'
62-
63-
result = param.deserialise(value)
64-
65-
assert result == value

0 commit comments

Comments
 (0)