From 3f7442624aad0600d77a24059787a34f9f5a7d01 Mon Sep 17 00:00:00 2001 From: p1c2u Date: Sun, 2 Feb 2020 22:51:02 +0000 Subject: [PATCH] Move unmarshal out of schema models --- README.rst | 61 ----------- openapi_core/schema/media_types/models.py | 13 --- openapi_core/schema/parameters/models.py | 16 --- .../unmarshalling/schemas/factories.py | 3 + openapi_core/validation/request/shortcuts.py | 24 ++++- openapi_core/validation/request/validators.py | 83 +++++++++----- openapi_core/validation/response/shortcuts.py | 15 ++- .../validation/response/validators.py | 70 +++++++----- tests/integration/validation/test_petstore.py | 26 ++--- .../integration/validation/test_validators.py | 5 +- tests/unit/schema/test_media_types.py | 46 -------- tests/unit/schema/test_parameters.py | 52 +-------- tests/unit/unmarshalling/test_unmarshal.py | 102 ++++++++++++++++++ .../unit/validation/test_request_shortcuts.py | 24 +++-- .../validation/test_response_shortcuts.py | 12 ++- 15 files changed, 282 insertions(+), 270 deletions(-) create mode 100644 tests/unit/unmarshalling/test_unmarshal.py diff --git a/README.rst b/README.rst index f51282ff..97399a87 100644 --- a/README.rst +++ b/README.rst @@ -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 @@ -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`_). @@ -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 @@ -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 ***** @@ -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 @@ -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 ******* diff --git a/openapi_core/schema/media_types/models.py b/openapi_core/schema/media_types/models.py index 9a536c81..67858577 100644 --- a/openapi_core/schema/media_types/models.py +++ b/openapi_core/schema/media_types/models.py @@ -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 = { @@ -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) diff --git a/openapi_core/schema/parameters/models.py b/openapi_core/schema/parameters/models.py index 768f72ea..db5ccaac 100644 --- a/openapi_core/schema/parameters/models.py +++ b/openapi_core/schema/parameters/models.py @@ -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__) @@ -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) diff --git a/openapi_core/unmarshalling/schemas/factories.py b/openapi_core/unmarshalling/schemas/factories.py index 9b53cc96..22224204 100644 --- a/openapi_core/unmarshalling/schemas/factories.py +++ b/openapi_core/unmarshalling/schemas/factories.py @@ -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 ( @@ -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) diff --git a/openapi_core/validation/request/shortcuts.py b/openapi_core/validation/request/shortcuts.py index 2f77d119..83ed4abb 100644 --- a/openapi_core/validation/request/shortcuts.py +++ b/openapi_core/validation/request/shortcuts.py @@ -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 @@ -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): diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index fc5c30a5..2fc3199d 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -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, ) @@ -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( @@ -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 = [] @@ -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, {}) @@ -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, + ) diff --git a/openapi_core/validation/response/shortcuts.py b/openapi_core/validation/response/shortcuts.py index 39bf0815..7ea19f22 100644 --- a/openapi_core/validation/response/shortcuts.py +++ b/openapi_core/validation/response/shortcuts.py @@ -1,4 +1,6 @@ """OpenAPI core validation response shortcuts module""" +import warnings + from openapi_core.validation.response.validators import ResponseValidator @@ -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, @@ -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 diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py index 4859f199..6ca479ae 100644 --- a/openapi_core/validation/response/validators.py +++ b/openapi_core/validation/response/validators.py @@ -7,6 +7,9 @@ InvalidResponse, MissingResponseContent, ) from openapi_core.schema.servers.exceptions import InvalidServer +from openapi_core.unmarshalling.schemas.exceptions import ( + UnmarshalError, ValidateError, +) from openapi_core.validation.response.datatypes import ResponseValidationResult from openapi_core.validation.util import get_operation_pattern @@ -19,27 +22,10 @@ def __init__(self, spec, custom_formatters=None): def validate(self, request, response): try: - server = self.spec.get_server(request.full_url_pattern) - # don't process if server errors - except InvalidServer as exc: - return ResponseValidationResult([exc, ], None, None) - - operation_pattern = get_operation_pattern( - server.default_url, request.full_url_pattern - ) - - try: - operation = self.spec.get_operation( - operation_pattern, request.method) + operation_response = self._get_operation_response( + request, response) # don't process if operation errors - except InvalidOperation as exc: - return ResponseValidationResult([exc, ], None, None) - - try: - operation_response = operation.get_response( - str(response.status_code)) - # don't process if operation response errors - except InvalidResponse as exc: + except (InvalidServer, InvalidOperation, InvalidResponse) as exc: return ResponseValidationResult([exc, ], None, None) data, data_errors = self._get_data(response, operation_response) @@ -50,6 +36,33 @@ def validate(self, request, response): errors = data_errors + headers_errors return ResponseValidationResult(errors, data, headers) + 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_operation(self, request): + operation_pattern = self._get_operation_pattern(request) + + return self.spec.get_operation(operation_pattern, request.method) + + def _get_operation_response(self, request, response): + operation = self._get_operation(request) + + return operation.get_response(str(response.status_code)) + + def _validate_data(self, request, response): + try: + operation_response = self._get_operation_response( + request, response) + except (InvalidServer, InvalidOperation, InvalidResponse) as exc: + return ResponseValidationResult([exc, ], None, None) + + data, data_errors = self._get_data(response, operation_response) + return ResponseValidationResult(data_errors, data, None) + def _get_data(self, response, operation_response): errors = [] @@ -73,11 +86,8 @@ def _get_data(self, response, operation_response): errors.append(exc) else: try: - data = media_type.unmarshal( - casted, self.custom_formatters, - resolver=self.spec._resolver, - ) - except InvalidMediaTypeValue as exc: + data = self._unmarshal(media_type, casted) + except (ValidateError, UnmarshalError) as exc: errors.append(exc) return data, errors @@ -89,3 +99,13 @@ def _get_headers(self, response, operation_response): headers = {} return headers, 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, + ) diff --git a/tests/integration/validation/test_petstore.py b/tests/integration/validation/test_petstore.py index 006469f4..fc7b0a3c 100644 --- a/tests/integration/validation/test_petstore.py +++ b/tests/integration/validation/test_petstore.py @@ -6,9 +6,7 @@ from six import text_type from openapi_core.extensions.models.models import BaseModel -from openapi_core.schema.media_types.exceptions import ( - InvalidContentType, InvalidMediaTypeValue, -) +from openapi_core.schema.media_types.exceptions import InvalidContentType from openapi_core.schema.parameters.exceptions import ( MissingRequiredParameter, InvalidParameterValue, EmptyParameterValue, ) @@ -175,14 +173,12 @@ def test_get_pets_invalid_response(self, spec, response_validator): response_result = response_validator.validate(request, response) - original_exc = response_result.errors[0].original_exception + schema_errors = response_result.errors[0].schema_errors assert response_result.errors == [ - InvalidMediaTypeValue( - original_exception=InvalidSchemaValue( - type=SchemaType.OBJECT, - value=data_json, - schema_errors=original_exc.schema_errors, - ), + InvalidSchemaValue( + type=SchemaType.OBJECT, + value=data_json, + schema_errors=schema_errors, ), ] assert response_result.data is None @@ -575,7 +571,7 @@ def test_post_no_one_of_schema(self, spec, spec_dict): }, ) - with pytest.raises(InvalidMediaTypeValue): + with pytest.raises(InvalidSchemaValue): validate_body(spec, request) def test_post_cats_only_required_body(self, spec, spec_dict): @@ -915,7 +911,7 @@ def test_post_tags_extra_body_properties(self, spec, spec_dict): assert parameters == RequestParameters() - with pytest.raises(InvalidMediaTypeValue): + with pytest.raises(InvalidSchemaValue): validate_body(spec, request) def test_post_tags_empty_body(self, spec, spec_dict): @@ -933,7 +929,7 @@ def test_post_tags_empty_body(self, spec, spec_dict): assert parameters == RequestParameters() - with pytest.raises(InvalidMediaTypeValue): + with pytest.raises(InvalidSchemaValue): validate_body(spec, request) def test_post_tags_wrong_property_type(self, spec): @@ -951,7 +947,7 @@ def test_post_tags_wrong_property_type(self, spec): assert parameters == RequestParameters() - with pytest.raises(InvalidMediaTypeValue): + with pytest.raises(InvalidSchemaValue): validate_body(spec, request) def test_post_tags_additional_properties( @@ -1110,7 +1106,7 @@ def test_post_tags_created_invalid_type( ) parameters = validate_parameters(spec, request) - with pytest.raises(InvalidMediaTypeValue): + with pytest.raises(InvalidSchemaValue): validate_body(spec, request) assert parameters == RequestParameters() diff --git a/tests/integration/validation/test_validators.py b/tests/integration/validation/test_validators.py index b3f98eae..09126be0 100644 --- a/tests/integration/validation/test_validators.py +++ b/tests/integration/validation/test_validators.py @@ -18,6 +18,7 @@ from openapi_core.schema.servers.exceptions import InvalidServer from openapi_core.shortcuts import create_spec from openapi_core.testing import MockRequest, MockResponse +from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue from openapi_core.validation.request.datatypes import RequestParameters from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.response.validators import ResponseValidator @@ -465,7 +466,7 @@ def test_invalid_media_type_value(self, validator): result = validator.validate(request, response) assert len(result.errors) == 1 - assert type(result.errors[0]) == InvalidMediaTypeValue + assert type(result.errors[0]) == InvalidSchemaValue assert result.data is None assert result.headers == {} @@ -485,7 +486,7 @@ def test_invalid_value(self, validator): result = validator.validate(request, response) assert len(result.errors) == 1 - assert type(result.errors[0]) == InvalidMediaTypeValue + assert type(result.errors[0]) == InvalidSchemaValue assert result.data is None assert result.headers == {} diff --git a/tests/unit/schema/test_media_types.py b/tests/unit/schema/test_media_types.py index 375f51d7..77cbd351 100644 --- a/tests/unit/schema/test_media_types.py +++ b/tests/unit/schema/test_media_types.py @@ -1,9 +1,4 @@ -import pytest - -from openapi_core.schema.media_types.exceptions import InvalidMediaTypeValue from openapi_core.schema.media_types.models import MediaType -from openapi_core.schema.schemas.models import Schema -from openapi_core.unmarshalling.schemas.formatters import Formatter class TestMediaTypeCast(object): @@ -15,44 +10,3 @@ def test_empty(self): result = media_type.cast(value) assert result == value - - -class TestParameterUnmarshal(object): - - def test_empty(self): - media_type = MediaType('application/json') - value = '' - - result = media_type.unmarshal(value) - - assert result == value - - def test_schema_type_invalid(self): - schema = Schema('integer', _source={'type': 'integer'}) - media_type = MediaType('application/json', schema=schema) - value = 'test' - - with pytest.raises(InvalidMediaTypeValue): - media_type.unmarshal(value) - - def test_schema_custom_format_invalid(self): - - class CustomFormatter(Formatter): - def unmarshal(self, value): - raise ValueError - formatter = CustomFormatter() - custom_format = 'custom' - custom_formatters = { - custom_format: formatter, - } - schema = Schema( - 'string', - schema_format=custom_format, - _source={'type': 'string', 'format': 'custom'}, - ) - media_type = MediaType('application/json', schema=schema) - value = 'test' - - with pytest.raises(InvalidMediaTypeValue): - media_type.unmarshal( - value, custom_formatters=custom_formatters) diff --git a/tests/unit/schema/test_parameters.py b/tests/unit/schema/test_parameters.py index 93f57907..ae7a98fd 100644 --- a/tests/unit/schema/test_parameters.py +++ b/tests/unit/schema/test_parameters.py @@ -1,12 +1,10 @@ import pytest from openapi_core.schema.parameters.exceptions import ( - EmptyParameterValue, InvalidParameterValue, + EmptyParameterValue, ) from openapi_core.schema.parameters.enums import ParameterStyle from openapi_core.schema.parameters.models import Parameter -from openapi_core.schema.schemas.models import Schema -from openapi_core.unmarshalling.schemas.formatters import Formatter class TestParameterInit(object): @@ -65,51 +63,3 @@ def test_query_valid(self): result = param.cast(value) assert result == value - - -class TestParameterUnmarshal(object): - - def test_query_valid(self): - param = Parameter('param', 'query') - value = 'test' - - result = param.unmarshal(value) - - assert result == value - - def test_query_allow_empty_value(self): - param = Parameter('param', 'query', allow_empty_value=True) - value = '' - - result = param.unmarshal(value) - - assert result == value - - def test_query_schema_type_invalid(self): - schema = Schema('integer', _source={'type': 'integer'}) - param = Parameter('param', 'query', schema=schema) - value = 'test' - - with pytest.raises(InvalidParameterValue): - param.unmarshal(value) - - def test_query_schema_custom_format_invalid(self): - - class CustomFormatter(Formatter): - def unmarshal(self, value): - raise ValueError - formatter = CustomFormatter() - custom_format = 'custom' - custom_formatters = { - custom_format: formatter, - } - schema = Schema( - 'string', - schema_format=custom_format, - _source={'type': 'string', 'format': 'custom'}, - ) - param = Parameter('param', 'query', schema=schema) - value = 'test' - - with pytest.raises(InvalidParameterValue): - param.unmarshal(value, custom_formatters=custom_formatters) diff --git a/tests/unit/unmarshalling/test_unmarshal.py b/tests/unit/unmarshalling/test_unmarshal.py new file mode 100644 index 00000000..718e024e --- /dev/null +++ b/tests/unit/unmarshalling/test_unmarshal.py @@ -0,0 +1,102 @@ +import pytest + +from openapi_core.schema.media_types.models import MediaType +from openapi_core.schema.parameters.models import Parameter +from openapi_core.schema.schemas.models import Schema +from openapi_core.unmarshalling.schemas.exceptions import ( + InvalidSchemaFormatValue, +) +from openapi_core.unmarshalling.schemas.factories import ( + SchemaUnmarshallersFactory, +) +from openapi_core.unmarshalling.schemas.formatters import Formatter + + +@pytest.fixture +def unmarshaller_factory(): + def create_unmarshaller(param_or_media_type, custom_formatters=None): + return SchemaUnmarshallersFactory( + custom_formatters=custom_formatters).create( + param_or_media_type.schema) + return create_unmarshaller + + +class TestParameterUnmarshal(object): + + def test_no_schema(self, unmarshaller_factory): + param = Parameter('param', 'query') + value = 'test' + + with pytest.raises(TypeError): + unmarshaller_factory(param).unmarshal(value) + + def test_schema_type_invalid(self, unmarshaller_factory): + schema = Schema('integer', _source={'type': 'integer'}) + param = Parameter('param', 'query', schema=schema) + value = 'test' + + with pytest.raises(InvalidSchemaFormatValue): + unmarshaller_factory(param).unmarshal(value) + + def test_schema_custom_format_invalid(self, unmarshaller_factory): + + class CustomFormatter(Formatter): + def unmarshal(self, value): + raise ValueError + formatter = CustomFormatter() + custom_format = 'custom' + custom_formatters = { + custom_format: formatter, + } + schema = Schema( + 'string', + schema_format=custom_format, + _source={'type': 'string', 'format': 'custom'}, + ) + param = Parameter('param', 'query', schema=schema) + value = 'test' + + with pytest.raises(InvalidSchemaFormatValue): + unmarshaller_factory( + param, custom_formatters=custom_formatters).unmarshal(value) + + +class TestMediaTypeUnmarshal(object): + + def test_no_schema(self, unmarshaller_factory): + media_type = MediaType('application/json') + value = 'test' + + with pytest.raises(TypeError): + unmarshaller_factory(media_type).unmarshal(value) + + def test_schema_type_invalid(self, unmarshaller_factory): + schema = Schema('integer', _source={'type': 'integer'}) + media_type = MediaType('application/json', schema=schema) + value = 'test' + + with pytest.raises(InvalidSchemaFormatValue): + unmarshaller_factory(media_type).unmarshal(value) + + def test_schema_custom_format_invalid(self, unmarshaller_factory): + + class CustomFormatter(Formatter): + def unmarshal(self, value): + raise ValueError + formatter = CustomFormatter() + custom_format = 'custom' + custom_formatters = { + custom_format: formatter, + } + schema = Schema( + 'string', + schema_format=custom_format, + _source={'type': 'string', 'format': 'custom'}, + ) + media_type = MediaType('application/json', schema=schema) + value = 'test' + + with pytest.raises(InvalidSchemaFormatValue): + unmarshaller_factory( + media_type, custom_formatters=custom_formatters).unmarshal( + value) diff --git a/tests/unit/validation/test_request_shortcuts.py b/tests/unit/validation/test_request_shortcuts.py index 7d3f4eb5..2b984cfb 100644 --- a/tests/unit/validation/test_request_shortcuts.py +++ b/tests/unit/validation/test_request_shortcuts.py @@ -12,7 +12,8 @@ class TestSpecValidateParameters(object): @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_parameters' ) def test_no_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -26,7 +27,8 @@ def test_no_request_factory(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_parameters' ) def test_no_request_factory_error(self, mock_validate): spec = mock.sentinel.spec @@ -39,7 +41,8 @@ def test_no_request_factory_error(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_parameters' ) def test_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -56,7 +59,8 @@ def test_request_factory(self, mock_validate): ) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_parameters' ) def test_request_factory_error(self, mock_validate): spec = mock.sentinel.spec @@ -75,7 +79,8 @@ def test_request_factory_error(self, mock_validate): class TestSpecValidateBody(object): @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_body' ) def test_no_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -89,7 +94,8 @@ def test_no_request_factory(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_body' ) def test_no_request_factory_error(self, mock_validate): spec = mock.sentinel.spec @@ -102,7 +108,8 @@ def test_no_request_factory_error(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_body' ) def test_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -119,7 +126,8 @@ def test_request_factory(self, mock_validate): ) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestValidator.validate' + 'openapi_core.validation.request.shortcuts.RequestValidator.' + '_validate_body' ) def test_request_factory_error(self, mock_validate): spec = mock.sentinel.spec diff --git a/tests/unit/validation/test_response_shortcuts.py b/tests/unit/validation/test_response_shortcuts.py index 9f2ded39..c42fc24e 100644 --- a/tests/unit/validation/test_response_shortcuts.py +++ b/tests/unit/validation/test_response_shortcuts.py @@ -10,7 +10,8 @@ class TestSpecValidateData(object): @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseValidator.validate' + 'openapi_core.validation.response.shortcuts.ResponseValidator.' + '_validate_data' ) def test_no_factories(self, mock_validate): spec = mock.sentinel.spec @@ -25,7 +26,8 @@ def test_no_factories(self, mock_validate): mock_validate.aasert_called_once_with(request, response) @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseValidator.validate' + 'openapi_core.validation.response.shortcuts.ResponseValidator.' + '_validate_data' ) def test_no_factories_error(self, mock_validate): spec = mock.sentinel.spec @@ -39,7 +41,8 @@ def test_no_factories_error(self, mock_validate): mock_validate.aasert_called_once_with(request, response) @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseValidator.validate' + 'openapi_core.validation.response.shortcuts.ResponseValidator.' + '_validate_data' ) def test_factories(self, mock_validate): spec = mock.sentinel.spec @@ -62,7 +65,8 @@ def test_factories(self, mock_validate): ) @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseValidator.validate' + 'openapi_core.validation.response.shortcuts.ResponseValidator.' + '_validate_data' ) def test_factories_error(self, mock_validate): spec = mock.sentinel.spec