diff --git a/openapi_core/validation/shortcuts.py b/openapi_core/validation/shortcuts.py index 6a07bd3a..01f846af 100644 --- a/openapi_core/validation/shortcuts.py +++ b/openapi_core/validation/shortcuts.py @@ -83,8 +83,19 @@ def validate_request( cls: Optional[AnyRequestValidatorType] = None, **validator_kwargs: Any, ) -> RequestValidationResult: + if isinstance(spec, (Request, WebhookRequest)) and isinstance( + request, Spec + ): + warnings.warn( + "spec parameter as a first argument is deprecated. " + "Move it to second argument instead.", + DeprecationWarning, + ) + request, spec = spec, request if not isinstance(request, (Request, WebhookRequest)): - raise TypeError("'request' is not (Webhook)Request") + raise TypeError("'request' argument is not type of (Webhook)Request") + if not isinstance(spec, Spec): + raise TypeError("'spec' argument is not type of Spec") if validator is not None and isinstance(request, Request): warnings.warn( "validator parameter is deprecated. Use cls instead.", @@ -113,18 +124,33 @@ def validate_request( def validate_response( - request: AnyRequest, - response: Response, - spec: Spec, + request: Union[Request, WebhookRequest, Spec], + response: Union[Response, Request, WebhookRequest], + spec: Union[Spec, Response], base_url: Optional[str] = None, validator: Optional[SpecResponseValidatorProxy] = None, cls: Optional[AnyResponseValidatorType] = None, **validator_kwargs: Any, ) -> ResponseValidationResult: + if ( + isinstance(request, Spec) + and isinstance(response, (Request, WebhookRequest)) + and isinstance(spec, Response) + ): + warnings.warn( + "spec parameter as a first argument is deprecated. " + "Move it to third argument instead.", + DeprecationWarning, + ) + args = request, response, spec + spec, request, response = args + if not isinstance(request, (Request, WebhookRequest)): - raise TypeError("'request' is not (Webhook)Request") + raise TypeError("'request' argument is not type of (Webhook)Request") if not isinstance(response, Response): - raise TypeError("'response' is not Response") + raise TypeError("'response' argument is not type of Response") + if not isinstance(spec, Spec): + raise TypeError("'spec' argument is not type of Spec") if validator is not None and isinstance(request, Request): warnings.warn( "validator parameter is deprecated. Use cls instead.", diff --git a/tests/unit/validation/conftest.py b/tests/unit/validation/conftest.py new file mode 100644 index 00000000..ea3361fb --- /dev/null +++ b/tests/unit/validation/conftest.py @@ -0,0 +1,18 @@ +import pytest + +from openapi_core import Spec + + +@pytest.fixture +def spec_v30(): + return Spec.from_dict({"openapi": "3.0"}, validator=None) + + +@pytest.fixture +def spec_v31(): + return Spec.from_dict({"openapi": "3.1"}, validator=None) + + +@pytest.fixture +def spec_invalid(): + return Spec.from_dict({}, validator=None) diff --git a/tests/unit/validation/test_shortcuts.py b/tests/unit/validation/test_shortcuts.py index 31c21362..8d9c5189 100644 --- a/tests/unit/validation/test_shortcuts.py +++ b/tests/unit/validation/test_shortcuts.py @@ -18,28 +18,44 @@ class TestValidateRequest: - def test_spec_not_detected(self): - spec = {} + def test_spec_not_detected(self, spec_invalid): request = mock.Mock(spec=Request) with pytest.raises(ValidatorDetectError): - validate_request(request, spec=spec) + validate_request(request, spec=spec_invalid) - def test_request_type_error(self): - spec = {"openapi": "3.1"} + def test_request_type_error(self, spec_v31): request = mock.sentinel.request + with pytest.raises(TypeError): + validate_request(request, spec=spec_v31) + + def test_spec_type_error(self): + request = mock.Mock(spec=Request) + spec = mock.sentinel.spec + with pytest.raises(TypeError): validate_request(request, spec=spec) @mock.patch( "openapi_core.validation.request.validators.RequestValidator.validate", ) - def test_request(self, mock_validate): - spec = {"openapi": "3.1"} + def test_request(self, mock_validate, spec_v31): + request = mock.Mock(spec=Request) + + result = validate_request(request, spec=spec_v31) + + assert result == mock_validate.return_value + mock_validate.validate.aasert_called_once_with(request) + + @mock.patch( + "openapi_core.validation.request.validators.RequestValidator.validate", + ) + def test_spec_as_first_arg_deprecated(self, mock_validate, spec_v31): request = mock.Mock(spec=Request) - result = validate_request(request, spec=spec) + with pytest.warns(DeprecationWarning): + result = validate_request(spec_v31, request) assert result == mock_validate.return_value mock_validate.validate.aasert_called_once_with(request) @@ -47,33 +63,32 @@ def test_request(self, mock_validate): @mock.patch( "openapi_core.validation.request.validators.RequestValidator.validate", ) - def test_request_error(self, mock_validate): - spec = {"openapi": "3.1"} + def test_request_error(self, mock_validate, spec_v31): request = mock.Mock(spec=Request) mock_validate.return_value = ResultMock(error_to_raise=ValueError) with pytest.raises(ValueError): - validate_request(request, spec=spec) + validate_request(request, spec=spec_v31) mock_validate.aasert_called_once_with(request) - def test_validator(self): - spec = mock.sentinel.spec + def test_validator(self, spec_v31): request = mock.Mock(spec=Request) validator = mock.Mock(spec=RequestValidator) with pytest.warns(DeprecationWarning): - result = validate_request(request, spec=spec, validator=validator) + result = validate_request( + request, spec=spec_v31, validator=validator + ) assert result == validator.validate.return_value validator.validate.aasert_called_once_with(request) - def test_validator_cls(self): - spec = mock.sentinel.spec + def test_validator_cls(self, spec_v31): request = mock.Mock(spec=Request) validator_cls = mock.Mock(spec=RequestValidator) - result = validate_request(request, spec=spec, cls=validator_cls) + result = validate_request(request, spec=spec_v31, cls=validator_cls) assert result == validator_cls().validate.return_value validator_cls().validate.aasert_called_once_with(request) @@ -82,69 +97,70 @@ def test_validator_cls(self): "openapi_core.validation.request.validators.WebhookRequestValidator." "validate", ) - def test_webhook_request(self, mock_validate): - spec = {"openapi": "3.1"} + def test_webhook_request(self, mock_validate, spec_v31): request = mock.Mock(spec=WebhookRequest) - result = validate_request(request, spec=spec) + result = validate_request(request, spec=spec_v31) assert result == mock_validate.return_value mock_validate.validate.aasert_called_once_with(request) - def test_webhook_request_validator_not_found(self): - spec = {"openapi": "3.0"} + def test_webhook_request_validator_not_found(self, spec_v30): request = mock.Mock(spec=WebhookRequest) with pytest.raises(ValidatorDetectError): - validate_request(request, spec=spec) + validate_request(request, spec=spec_v30) @mock.patch( "openapi_core.validation.request.validators.WebhookRequestValidator." "validate", ) - def test_webhook_request_error(self, mock_validate): - spec = {"openapi": "3.1"} + def test_webhook_request_error(self, mock_validate, spec_v31): request = mock.Mock(spec=WebhookRequest) mock_validate.return_value = ResultMock(error_to_raise=ValueError) with pytest.raises(ValueError): - validate_request(request, spec=spec) + validate_request(request, spec=spec_v31) mock_validate.aasert_called_once_with(request) - def test_webhook_validator_cls(self): - spec = mock.sentinel.spec + def test_webhook_validator_cls(self, spec_v31): request = mock.Mock(spec=WebhookRequest) validator_cls = mock.Mock(spec=WebhookRequestValidator) - result = validate_request(request, spec=spec, cls=validator_cls) + result = validate_request(request, spec=spec_v31, cls=validator_cls) assert result == validator_cls().validate.return_value validator_cls().validate.aasert_called_once_with(request) class TestValidateResponse: - def test_spec_not_detected(self): - spec = {} + def test_spec_not_detected(self, spec_invalid): request = mock.Mock(spec=Request) response = mock.Mock(spec=Response) with pytest.raises(ValidatorDetectError): - validate_response(request, response, spec=spec) + validate_response(request, response, spec=spec_invalid) - def test_request_type_error(self): - spec = {"openapi": "3.1"} + def test_request_type_error(self, spec_v31): request = mock.sentinel.request response = mock.Mock(spec=Response) with pytest.raises(TypeError): - validate_response(request, response, spec=spec) + validate_response(request, response, spec=spec_v31) - def test_response_type_error(self): - spec = {"openapi": "3.1"} + def test_response_type_error(self, spec_v31): request = mock.Mock(spec=Request) response = mock.sentinel.response + with pytest.raises(TypeError): + validate_response(request, response, spec=spec_v31) + + def test_spec_type_error(self): + request = mock.Mock(spec=Request) + response = mock.Mock(spec=Response) + spec = mock.sentinel.spec + with pytest.raises(TypeError): validate_response(request, response, spec=spec) @@ -152,12 +168,24 @@ def test_response_type_error(self): "openapi_core.validation.response.validators.ResponseValidator." "validate", ) - def test_request_response(self, mock_validate): - spec = {"openapi": "3.1"} + def test_request_response(self, mock_validate, spec_v31): + request = mock.Mock(spec=Request) + response = mock.Mock(spec=Response) + + result = validate_response(request, response, spec=spec_v31) + + assert result == mock_validate.return_value + mock_validate.aasert_called_once_with(request, response) + + @mock.patch( + "openapi_core.validation.response.validators.ResponseValidator." + "validate", + ) + def test_spec_as_first_arg_deprecated(self, mock_validate, spec_v31): request = mock.Mock(spec=Request) response = mock.Mock(spec=Response) - result = validate_response(request, response, spec=spec) + result = validate_response(spec_v31, request, response) assert result == mock_validate.return_value mock_validate.aasert_called_once_with(request, response) @@ -166,62 +194,57 @@ def test_request_response(self, mock_validate): "openapi_core.validation.response.validators.ResponseValidator." "validate", ) - def test_request_response_error(self, mock_validate): - spec = {"openapi": "3.1"} + def test_request_response_error(self, mock_validate, spec_v31): request = mock.Mock(spec=Request) response = mock.Mock(spec=Response) mock_validate.return_value = ResultMock(error_to_raise=ValueError) with pytest.raises(ValueError): - validate_response(request, response, spec=spec) + validate_response(request, response, spec=spec_v31) mock_validate.aasert_called_once_with(request, response) - def test_validator(self): - spec = mock.sentinel.spec + def test_validator(self, spec_v31): request = mock.Mock(spec=Request) response = mock.Mock(spec=Response) validator = mock.Mock(spec=ResponseValidator) with pytest.warns(DeprecationWarning): result = validate_response( - request, response, spec=spec, validator=validator + request, response, spec=spec_v31, validator=validator ) assert result == validator.validate.return_value validator.validate.aasert_called_once_with(request) - def test_validator_cls(self): - spec = mock.sentinel.spec + def test_validator_cls(self, spec_v31): request = mock.Mock(spec=Request) response = mock.Mock(spec=Response) validator_cls = mock.Mock(spec=ResponseValidator) result = validate_response( - request, response, spec=spec, cls=validator_cls + request, response, spec=spec_v31, cls=validator_cls ) assert result == validator_cls().validate.return_value validator_cls().validate.aasert_called_once_with(request) - def test_webhook_response_validator_not_found(self): - spec = {"openapi": "3.0"} + def test_webhook_response_validator_not_found(self, spec_v30): request = mock.Mock(spec=WebhookRequest) response = mock.Mock(spec=Response) with pytest.raises(ValidatorDetectError): - validate_response(request, response, spec=spec) + validate_response(request, response, spec=spec_v30) @mock.patch( "openapi_core.validation.response.validators.WebhookResponseValidator." "validate", ) - def test_webhook_request(self, mock_validate): - spec = {"openapi": "3.1"} + def test_webhook_request(self, mock_validate, spec_v31): request = mock.Mock(spec=WebhookRequest) response = mock.Mock(spec=Response) - result = validate_response(request, response, spec=spec) + result = validate_response(request, response, spec=spec_v31) assert result == mock_validate.return_value mock_validate.aasert_called_once_with(request, response) @@ -230,25 +253,23 @@ def test_webhook_request(self, mock_validate): "openapi_core.validation.response.validators.WebhookResponseValidator." "validate", ) - def test_webhook_request_error(self, mock_validate): - spec = {"openapi": "3.1"} + def test_webhook_request_error(self, mock_validate, spec_v31): request = mock.Mock(spec=WebhookRequest) response = mock.Mock(spec=Response) mock_validate.return_value = ResultMock(error_to_raise=ValueError) with pytest.raises(ValueError): - validate_response(request, response, spec=spec) + validate_response(request, response, spec=spec_v31) mock_validate.aasert_called_once_with(request, response) - def test_webhook_response_cls(self): - spec = mock.sentinel.spec + def test_webhook_response_cls(self, spec_v31): request = mock.Mock(spec=WebhookRequest) response = mock.Mock(spec=Response) validator_cls = mock.Mock(spec=WebhookResponseValidator) result = validate_response( - request, response, spec=spec, cls=validator_cls + request, response, spec=spec_v31, cls=validator_cls ) assert result == validator_cls().validate.return_value