Skip to content

Commit 8048578

Browse files
authored
Merge pull request #191 from p1c2u/refactor/move-cast-out-of-schema-models
Move deserialize/cast out of schema models
2 parents 2c1a6c1 + 4044483 commit 8048578

File tree

27 files changed

+352
-285
lines changed

27 files changed

+352
-285
lines changed

openapi_core/casting/schemas/casters.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1+
from openapi_core.casting.schemas.exceptions import CastError
12
from openapi_core.schema.schemas.types import NoValue
23

34

45
class PrimitiveCaster(object):
56

6-
def __init__(self, caster_callable):
7+
def __init__(self, schema, caster_callable):
8+
self.schema = schema
79
self.caster_callable = caster_callable
810

911
def __call__(self, value):
1012
if value in (None, NoValue):
1113
return value
12-
return self.caster_callable(value)
14+
try:
15+
return self.caster_callable(value)
16+
except (ValueError, TypeError):
17+
raise CastError(value, self.schema.type.value)
1318

1419

1520
class DummyCaster(object):

openapi_core/casting/schemas/factories.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,24 @@
88

99
class SchemaCastersFactory(object):
1010

11-
DUMMY_CASTER = DummyCaster()
11+
DUMMY_CASTERS = [
12+
SchemaType.STRING, SchemaType.OBJECT, SchemaType.ANY,
13+
]
1214
PRIMITIVE_CASTERS = {
13-
SchemaType.STRING: DUMMY_CASTER,
14-
SchemaType.INTEGER: PrimitiveCaster(int),
15-
SchemaType.NUMBER: PrimitiveCaster(float),
16-
SchemaType.BOOLEAN: PrimitiveCaster(forcebool),
17-
SchemaType.OBJECT: DUMMY_CASTER,
18-
SchemaType.ANY: DUMMY_CASTER,
15+
SchemaType.INTEGER: int,
16+
SchemaType.NUMBER: float,
17+
SchemaType.BOOLEAN: forcebool,
1918
}
2019
COMPLEX_CASTERS = {
2120
SchemaType.ARRAY: ArrayCaster,
2221
}
2322

2423
def create(self, schema):
25-
if schema.type in self.PRIMITIVE_CASTERS:
26-
return self.PRIMITIVE_CASTERS[schema.type]
24+
if schema.type in self.DUMMY_CASTERS:
25+
return DummyCaster()
26+
elif schema.type in self.PRIMITIVE_CASTERS:
27+
caster_callable = self.PRIMITIVE_CASTERS[schema.type]
28+
return PrimitiveCaster(schema, caster_callable)
2729
elif schema.type in self.COMPLEX_CASTERS:
2830
caster_class = self.COMPLEX_CASTERS[schema.type]
29-
return caster_class(schema=schema, casters_factory=self)
31+
return caster_class(schema, self)

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/media_types/__init__.py

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from openapi_core.deserializing.exceptions import DeserializeError
2+
3+
4+
class PrimitiveDeserializer(object):
5+
6+
def __init__(self, mimetype, deserializer_callable):
7+
self.mimetype = mimetype
8+
self.deserializer_callable = deserializer_callable
9+
10+
def __call__(self, value):
11+
try:
12+
return self.deserializer_callable(value)
13+
except (ValueError, TypeError, AttributeError):
14+
raise DeserializeError(value, self.mimetype)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from openapi_core.schema.media_types.util import json_loads
2+
3+
from openapi_core.deserializing.media_types.deserializers import (
4+
PrimitiveDeserializer,
5+
)
6+
7+
8+
class MediaTypeDeserializersFactory(object):
9+
10+
MEDIA_TYPE_DESERIALIZERS = {
11+
'application/json': json_loads,
12+
}
13+
14+
def create(self, media_type):
15+
deserialize_callable = self.MEDIA_TYPE_DESERIALIZERS.get(
16+
media_type.mimetype, lambda x: x)
17+
return PrimitiveDeserializer(
18+
media_type.mimetype, deserialize_callable)

openapi_core/deserializing/parameters/__init__.py

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
7+
8+
class PrimitiveDeserializer(object):
9+
10+
def __init__(self, param, deserializer_callable):
11+
self.param = param
12+
self.deserializer_callable = deserializer_callable
13+
14+
def __call__(self, value):
15+
if (self.param.location == ParameterLocation.QUERY and value == "" and
16+
not self.param.allow_empty_value):
17+
raise EmptyParameterValue(
18+
value, self.param.style, self.param.name)
19+
20+
if not self.param.aslist or self.param.explode:
21+
return value
22+
try:
23+
return self.deserializer_callable(value)
24+
except (ValueError, TypeError, AttributeError):
25+
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)

0 commit comments

Comments
 (0)