Skip to content

Move unmarshal out of schema models #188

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
Feb 2, 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
61 changes: 0 additions & 61 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,6 @@ and unmarshal request data from validation result
# get body
validated_body = result.body

or use shortcuts for simple validation

.. code-block:: python

from openapi_core import validate_parameters, validate_body

validated_params = validate_parameters(spec, request)
validated_body = validate_body(spec, request)

Request object should be instance of OpenAPIRequest class (See `Integrations`_).

Response
Expand Down Expand Up @@ -117,14 +108,6 @@ and unmarshal response data from validation result
# get data
validated_data = result.data

or use shortcuts for simple validation

.. code-block:: python

from openapi_core import validate_data

validated_data = validate_data(spec, request, response)

Response object should be instance of OpenAPIResponse class (See `Integrations`_).


Expand All @@ -145,17 +128,6 @@ For Django 2.2 you can use DjangoOpenAPIRequest a Django request factory:
validator = RequestValidator(spec)
result = validator.validate(openapi_request)

or simply specify request factory for shortcuts

.. code-block:: python

from openapi_core import validate_parameters, validate_body

validated_params = validate_parameters(
spec, request, request_factory=DjangoOpenAPIRequest)
validated_body = validate_body(
spec, request, request_factory=DjangoOpenAPIRequest)

You can use DjangoOpenAPIResponse as a Django response factory:

.. code-block:: python
Expand All @@ -167,17 +139,6 @@ You can use DjangoOpenAPIResponse as a Django response factory:
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)

or simply specify response factory for shortcuts

.. code-block:: python

from openapi_core import validate_parameters, validate_body

validated_data = validate_data(
spec, request, response,
request_factory=DjangoOpenAPIRequest,
response_factory=DjangoOpenAPIResponse)

Flask
*****

Expand Down Expand Up @@ -247,17 +208,6 @@ You can use FlaskOpenAPIRequest a Flask/Werkzeug request factory:
validator = RequestValidator(spec)
result = validator.validate(openapi_request)

or simply specify request factory for shortcuts

.. code-block:: python

from openapi_core import validate_parameters, validate_body

validated_params = validate_parameters(
spec, request, request_factory=FlaskOpenAPIRequest)
validated_body = validate_body(
spec, request, request_factory=FlaskOpenAPIRequest)

You can use FlaskOpenAPIResponse as a Flask/Werkzeug response factory:

.. code-block:: python
Expand All @@ -269,17 +219,6 @@ You can use FlaskOpenAPIResponse as a Flask/Werkzeug response factory:
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)

or simply specify response factory for shortcuts

.. code-block:: python

from openapi_core import validate_parameters, validate_body

validated_data = validate_data(
spec, request, response,
request_factory=FlaskOpenAPIRequest,
response_factory=FlaskOpenAPIResponse)

Pyramid
*******

Expand Down
13 changes: 0 additions & 13 deletions openapi_core/schema/media_types/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
from openapi_core.schema.media_types.exceptions import InvalidMediaTypeValue
from openapi_core.schema.media_types.util import json_loads
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.unmarshalling.schemas.exceptions import (
UnmarshalError, ValidateError,
)


MEDIA_TYPE_DESERIALIZERS = {
Expand Down Expand Up @@ -47,13 +44,3 @@ def cast(self, value):
return self.schema.cast(deserialized)
except CastError as exc:
raise InvalidMediaTypeValue(exc)

def unmarshal(self, value, custom_formatters=None, resolver=None):
if not self.schema:
return value

try:
return self.schema.unmarshal(
value, resolver=resolver, custom_formatters=custom_formatters)
except (ValidateError, UnmarshalError) as exc:
raise InvalidMediaTypeValue(exc)
16 changes: 0 additions & 16 deletions openapi_core/schema/parameters/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
)
from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.unmarshalling.schemas.exceptions import (
UnmarshalError, ValidateError,
)

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -114,16 +111,3 @@ def cast(self, value):
return self.schema.cast(deserialized)
except CastError as exc:
raise InvalidParameterValue(self.name, exc)

def unmarshal(self, value, custom_formatters=None, resolver=None):
if not self.schema:
return value

try:
return self.schema.unmarshal(
value,
resolver=resolver,
custom_formatters=custom_formatters,
)
except (ValidateError, UnmarshalError) as exc:
raise InvalidParameterValue(self.name, exc)
3 changes: 3 additions & 0 deletions openapi_core/unmarshalling/schemas/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import warnings

from openapi_core.schema.schemas.enums import SchemaType, SchemaFormat
from openapi_core.schema.schemas.models import Schema
from openapi_core.schema_validator import OAS30Validator
from openapi_core.schema_validator import oas30_format_checker
from openapi_core.unmarshalling.schemas.exceptions import (
Expand Down Expand Up @@ -36,6 +37,8 @@ def __init__(self, resolver=None, custom_formatters=None):

def create(self, schema, type_override=None):
"""Create unmarshaller from the schema."""
if not isinstance(schema, Schema):
raise TypeError("schema not type of Schema")
if schema.deprecated:
warnings.warn("The schema is deprecated", DeprecationWarning)

Expand Down
24 changes: 21 additions & 3 deletions openapi_core/validation/request/shortcuts.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""OpenAPI core validation request shortcuts module"""
from functools import partial
import warnings

from openapi_core.schema.media_types.exceptions import OpenAPIMediaTypeError
from openapi_core.schema.parameters.exceptions import OpenAPIParameterError
Expand Down Expand Up @@ -28,8 +28,26 @@ def validate_request(validator, request, failsafe=None):
return result


validate_parameters = partial(validate_request, failsafe=ERRORS_BODY)
validate_body = partial(validate_request, failsafe=ERRORS_PARAMETERS)
def validate_parameters(validator, request):
warnings.warn(
"validate_parameters shortcut is deprecated, "
"use validator.validate instead",
DeprecationWarning,
)
result = validator._validate_parameters(request)
result.raise_for_errors()
return result


def validate_body(validator, request):
warnings.warn(
"validate_body shortcut is deprecated, "
"use validator.validate instead",
DeprecationWarning,
)
result = validator._validate_body(request)
result.raise_for_errors()
return result


def spec_validate_parameters(spec, request, request_factory=None):
Expand Down
83 changes: 58 additions & 25 deletions openapi_core/validation/request/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from openapi_core.schema.paths.exceptions import InvalidPath
from openapi_core.schema.request_bodies.exceptions import MissingRequestBody
from openapi_core.schema.servers.exceptions import InvalidServer
from openapi_core.unmarshalling.schemas.exceptions import (
UnmarshalError, ValidateError,
)
from openapi_core.validation.request.datatypes import (
RequestParameters, RequestValidationResult,
)
Expand All @@ -26,25 +29,29 @@ def __init__(self, spec, custom_formatters=None):

def validate(self, request):
try:
server = self.spec.get_server(request.full_url_pattern)
# don't process if server errors
except InvalidServer as exc:
path = self._get_path(request)
operation = self._get_operation(request)
# don't process if operation errors
except (InvalidServer, InvalidPath, InvalidOperation) as exc:
return RequestValidationResult([exc, ], None, None)

operation_pattern = get_operation_pattern(
server.default_url, request.full_url_pattern
params, params_errors = self._get_parameters(
request, chain(
iteritems(operation.parameters),
iteritems(path.parameters)
)
)

try:
path = self.spec[operation_pattern]
except InvalidPath as exc:
return RequestValidationResult([exc, ], None, None)
body, body_errors = self._get_body(request, operation)

errors = params_errors + body_errors
return RequestValidationResult(errors, body, params)

def _validate_parameters(self, request):
try:
operation = self.spec.get_operation(
operation_pattern, request.method)
# don't process if operation errors
except InvalidOperation as exc:
path = self._get_path(request)
operation = self._get_operation(request)
except (InvalidServer, InvalidPath, InvalidOperation) as exc:
return RequestValidationResult([exc, ], None, None)

params, params_errors = self._get_parameters(
Expand All @@ -53,11 +60,33 @@ def validate(self, request):
iteritems(path.parameters)
)
)
return RequestValidationResult(params_errors, None, params)

def _validate_body(self, request):
try:
operation = self._get_operation(request)
except (InvalidServer, InvalidOperation) as exc:
return RequestValidationResult([exc, ], None, None)

body, body_errors = self._get_body(request, operation)
return RequestValidationResult(body_errors, body, None)

errors = params_errors + body_errors
return RequestValidationResult(errors, body, params)
def _get_operation_pattern(self, request):
server = self.spec.get_server(request.full_url_pattern)

return get_operation_pattern(
server.default_url, request.full_url_pattern
)

def _get_path(self, request):
operation_pattern = self._get_operation_pattern(request)

return self.spec[operation_pattern]

def _get_operation(self, request):
operation_pattern = self._get_operation_pattern(request)

return self.spec.get_operation(operation_pattern, request.method)

def _get_parameters(self, request, params):
errors = []
Expand Down Expand Up @@ -86,11 +115,8 @@ def _get_parameters(self, request, params):
continue

try:
unmarshalled = param.unmarshal(
casted, self.custom_formatters,
resolver=self.spec._resolver,
)
except OpenAPIParameterError as exc:
unmarshalled = self._unmarshal(param, casted)
except (ValidateError, UnmarshalError) as exc:
errors.append(exc)
else:
locations.setdefault(param.location.value, {})
Expand Down Expand Up @@ -121,11 +147,18 @@ def _get_body(self, request, operation):
errors.append(exc)
else:
try:
body = media_type.unmarshal(
casted, self.custom_formatters,
resolver=self.spec._resolver,
)
except InvalidMediaTypeValue as exc:
body = self._unmarshal(media_type, casted)
except (ValidateError, UnmarshalError) as exc:
errors.append(exc)

return body, errors

def _unmarshal(self, param_or_media_type, value):
if not param_or_media_type.schema:
return value

return param_or_media_type.schema.unmarshal(
value,
resolver=self.spec._resolver,
custom_formatters=self.custom_formatters,
)
15 changes: 14 additions & 1 deletion openapi_core/validation/response/shortcuts.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""OpenAPI core validation response shortcuts module"""
import warnings

from openapi_core.validation.response.validators import ResponseValidator


Expand All @@ -8,6 +10,17 @@ def validate_response(validator, request, response):
return result


def validate_data(validator, request, response):
warnings.warn(
"validate_data shortcut is deprecated, "
"use validator.validate instead",
DeprecationWarning,
)
result = validator._validate_data(request, response)
result.raise_for_errors()
return result


def spec_validate_data(
spec, request, response,
request_factory=None,
Expand All @@ -18,6 +31,6 @@ def spec_validate_data(
response = response_factory(response)

validator = ResponseValidator(spec)
result = validate_response(validator, request, response)
result = validate_data(validator, request, response)

return result.data
Loading