Skip to content

Move casters to separate subpackage #184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
34 changes: 34 additions & 0 deletions openapi_core/casting/schemas/casters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from openapi_core.schema.schemas.types import NoValue


class PrimitiveCaster(object):

def __init__(self, caster_callable):
self.caster_callable = caster_callable

def __call__(self, value):
if value in (None, NoValue):
return value
return self.caster_callable(value)


class DummyCaster(object):

def __call__(self, value):
return value


class ArrayCaster(object):

def __init__(self, schema, casters_factory):
self.schema = schema
self.casters_factory = casters_factory

@property
def items_caster(self):
return self.casters_factory.create(self.schema.items)

def __call__(self, value):
if value in (None, NoValue):
return value
return list(map(self.items_caster, value))
14 changes: 14 additions & 0 deletions openapi_core/casting/schemas/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import attr

from openapi_core.exceptions import OpenAPIError


@attr.s(hash=True)
class CastError(OpenAPIError):
"""Schema cast operation error"""
value = attr.ib()
type = attr.ib()

def __str__(self):
return "Failed to cast value {value} to type {type}".format(
value=self.value, type=self.type)
29 changes: 29 additions & 0 deletions openapi_core/casting/schemas/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from openapi_core.schema.schemas.enums import SchemaType

from openapi_core.casting.schemas.casters import (
PrimitiveCaster, DummyCaster, ArrayCaster
)
from openapi_core.casting.schemas.util import forcebool


class SchemaCastersFactory(object):

DUMMY_CASTER = DummyCaster()
PRIMITIVE_CASTERS = {
SchemaType.STRING: DUMMY_CASTER,
SchemaType.INTEGER: PrimitiveCaster(int),
SchemaType.NUMBER: PrimitiveCaster(float),
SchemaType.BOOLEAN: PrimitiveCaster(forcebool),
SchemaType.OBJECT: DUMMY_CASTER,
SchemaType.ANY: DUMMY_CASTER,
}
COMPLEX_CASTERS = {
SchemaType.ARRAY: ArrayCaster,
}

def create(self, schema):
if schema.type in self.PRIMITIVE_CASTERS:
return self.PRIMITIVE_CASTERS[schema.type]
elif schema.type in self.COMPLEX_CASTERS:
caster_class = self.COMPLEX_CASTERS[schema.type]
return caster_class(schema=schema, casters_factory=self)
10 changes: 10 additions & 0 deletions openapi_core/casting/schemas/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""OpenAPI core casting schemas util module"""
from distutils.util import strtobool
from six import string_types


def forcebool(val):
if isinstance(val, string_types):
val = strtobool(val)

return bool(val)
3 changes: 2 additions & 1 deletion openapi_core/schema/media_types/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

from openapi_core.schema.media_types.exceptions import InvalidMediaTypeValue
from openapi_core.schema.schemas.exceptions import (
CastError, ValidateError,
ValidateError,
)
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError


Expand Down
3 changes: 2 additions & 1 deletion openapi_core/schema/parameters/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
)
from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.schema.schemas.exceptions import (
CastError, ValidateError,
ValidateError,
)
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError

log = logging.getLogger(__name__)
Expand Down
11 changes: 0 additions & 11 deletions openapi_core/schema/schemas/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ class OpenAPISchemaError(OpenAPIMappingError):
pass


@attr.s(hash=True)
class CastError(OpenAPISchemaError):
"""Schema cast operation error"""
value = attr.ib()
type = attr.ib()

def __str__(self):
return "Failed to cast value {value} to type {type}".format(
value=self.value, type=self.type)


class ValidateError(OpenAPISchemaError):
"""Schema validate operation error"""
pass
Expand Down
37 changes: 7 additions & 30 deletions openapi_core/schema/schemas/models.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
"""OpenAPI core schemas models module"""
import attr
import logging
from collections import defaultdict
import re

from jsonschema.exceptions import ValidationError

from openapi_core.schema.schemas._format import oas30_format_checker
from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.schema.schemas.exceptions import (
CastError, InvalidSchemaValue,
)
from openapi_core.schema.schemas.exceptions import InvalidSchemaValue
from openapi_core.schema.schemas.types import NoValue
from openapi_core.schema.schemas.util import forcebool
from openapi_core.schema.schemas.validators import OAS30Validator
from openapi_core.unmarshalling.schemas.exceptions import (
UnmarshalValueError,
Expand All @@ -30,12 +26,6 @@ class Format(object):
class Schema(object):
"""Represents an OpenAPI Schema."""

TYPE_CAST_CALLABLE_GETTER = {
SchemaType.INTEGER: int,
SchemaType.NUMBER: float,
SchemaType.BOOLEAN: forcebool,
}

def __init__(
self, schema_type=None, properties=None, items=None,
schema_format=None, required=None, default=NoValue, nullable=False,
Expand Down Expand Up @@ -109,30 +99,17 @@ def get_all_properties_names(self):
all_properties = self.get_all_properties()
return set(all_properties.keys())

def get_cast_mapping(self):
mapping = self.TYPE_CAST_CALLABLE_GETTER.copy()
mapping.update({
SchemaType.ARRAY: self._cast_collection,
})

return defaultdict(lambda: lambda x: x, mapping)

def cast(self, value):
"""Cast value from string to schema type"""
if value in (None, NoValue):
return value

cast_mapping = self.get_cast_mapping()

cast_callable = cast_mapping[self.type]
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.casting.schemas.factories import SchemaCastersFactory
casters_factory = SchemaCastersFactory()
caster = casters_factory.create(self)
try:
return cast_callable(value)
except ValueError:
return caster(value)
except (ValueError, TypeError):
raise CastError(value, self.type)

def _cast_collection(self, value):
return list(map(self.items.cast, value))

def get_validator(self, resolver=None):
return OAS30Validator(
self.__dict__,
Expand Down