From afa1fe096ae018582de076846ff71340954551df Mon Sep 17 00:00:00 2001 From: p1c2u Date: Tue, 3 Mar 2026 19:12:08 +0000 Subject: [PATCH] Fix deprecation warnings for omitted params and headers --- openapi_core/validation/request/validators.py | 7 +-- .../validation/response/validators.py | 2 +- tests/integration/test_petstore.py | 24 +++----- .../test_response_unmarshaller.py | 30 ++++++++++ .../validation/test_request_validators.py | 56 +++++++++++++++++++ .../validation/test_response_validators.py | 27 +++++++++ 6 files changed, 126 insertions(+), 20 deletions(-) diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index 4decc3b7..c0050f87 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -202,16 +202,15 @@ def _get_parameter( self, parameters: RequestParameters, param: SchemaPath ) -> Any: name = (param / "name").read_str() + param_location = (param / "in").read_str() + location = parameters[param_location] deprecated = (param / "deprecated").read_bool(default=False) - if deprecated: + if deprecated and name in location: warnings.warn( f"{name} parameter is deprecated", DeprecationWarning, ) - param_location = (param / "in").read_str() - location = parameters[param_location] - try: value, _ = self._get_param_or_header_and_schema(param, location) except KeyError: diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py index b8661367..2a436082 100644 --- a/openapi_core/validation/response/validators.py +++ b/openapi_core/validation/response/validators.py @@ -175,7 +175,7 @@ def _get_header( self, headers: Mapping[str, Any], name: str, header: SchemaPath ) -> Any: deprecated = (header / "deprecated").read_bool(default=False) - if deprecated: + if deprecated and name in headers: warnings.warn( f"{name} header is deprecated", DeprecationWarning, diff --git a/tests/integration/test_petstore.py b/tests/integration/test_petstore.py index 11bfa250..d122ba49 100644 --- a/tests/integration/test_petstore.py +++ b/tests/integration/test_petstore.py @@ -532,18 +532,15 @@ def test_get_pets_raises_missing_required_param(self, spec): ) with pytest.warns( - DeprecationWarning, match="limit parameter is deprecated" + DeprecationWarning, + match="Use of allowEmptyValue property is deprecated", ): - with pytest.warns( - DeprecationWarning, - match="Use of allowEmptyValue property is deprecated", - ): - with pytest.raises(MissingRequiredParameter): - validate_request( - request, - spec=spec, - cls=V30RequestParametersValidator, - ) + with pytest.raises(MissingRequiredParameter): + validate_request( + request, + spec=spec, + cls=V30RequestParametersValidator, + ) result = unmarshal_request( request, spec=spec, cls=V30RequestBodyUnmarshaller @@ -2165,10 +2162,7 @@ def test_delete_tags_raises_missing_required_response_header( data = None response = MockResponse(data, status_code=200) - with pytest.warns(DeprecationWarning): - response_result = response_unmarshaller.unmarshal( - request, response - ) + response_result = response_unmarshaller.unmarshal(request, response) assert response_result.errors == [ MissingRequiredHeader(name="x-delete-confirm"), diff --git a/tests/integration/unmarshalling/test_response_unmarshaller.py b/tests/integration/unmarshalling/test_response_unmarshaller.py index 3c67cf60..f06f688c 100644 --- a/tests/integration/unmarshalling/test_response_unmarshaller.py +++ b/tests/integration/unmarshalling/test_response_unmarshaller.py @@ -19,6 +19,7 @@ from openapi_core.validation.response.exceptions import InvalidData from openapi_core.validation.response.exceptions import InvalidHeader from openapi_core.validation.response.exceptions import MissingData +from openapi_core.validation.response.exceptions import MissingRequiredHeader from openapi_core.validation.schemas.exceptions import InvalidSchemaValue @@ -173,6 +174,35 @@ def test_invalid_header(self, response_unmarshaller): assert result.data is None assert result.headers == {"x-delete-confirm": True} + def test_missing_deprecated_required_header(self, response_unmarshaller): + request = MockRequest( + self.host_url, + "delete", + "/v1/tags", + path_pattern="/v1/tags", + ) + response_json = { + "data": [ + { + "id": 1, + "name": "Sparky", + "ears": { + "healthy": True, + }, + }, + ], + } + response_data = json.dumps(response_json).encode() + response = MockResponse(response_data) + + result = response_unmarshaller.unmarshal(request, response) + + assert result.errors == [ + MissingRequiredHeader(name="x-delete-confirm") + ] + assert result.data is None + assert result.headers == {} + def test_get_pets(self, response_unmarshaller): request = MockRequest(self.host_url, "get", "/v1/pets") response_json = { diff --git a/tests/integration/validation/test_request_validators.py b/tests/integration/validation/test_request_validators.py index eaac8dbf..fcbed32f 100644 --- a/tests/integration/validation/test_request_validators.py +++ b/tests/integration/validation/test_request_validators.py @@ -2,6 +2,7 @@ import pytest +from openapi_core import OpenAPI from openapi_core import V30RequestValidator from openapi_core.templating.media_types.exceptions import MediaTypeNotFound from openapi_core.templating.paths.exceptions import OperationNotFound @@ -63,6 +64,61 @@ def test_missing_parameter(self, request_validator): with pytest.warns(DeprecationWarning): request_validator.validate(request) + def test_omitted_required_deprecated_parameter(self): + spec = OpenAPI.from_dict( + { + "openapi": "3.1.0", + "info": {"version": "0", "title": "test"}, + "paths": { + "/test": { + "get": { + "parameters": [ + { + "name": "foo", + "in": "query", + "schema": {}, + "deprecated": True, + "required": True, + }, + ] + } + } + }, + } + ) + + request = MockRequest("http://localhost", "get", "/test") + + with pytest.raises(MissingRequiredParameter): + spec.validate_request(request) + + def test_omitted_optional_deprecated_parameter(self): + spec = OpenAPI.from_dict( + { + "openapi": "3.1.0", + "info": {"version": "0", "title": "test"}, + "paths": { + "/test": { + "get": { + "parameters": [ + { + "name": "foo", + "in": "query", + "schema": {}, + "deprecated": True, + }, + ] + } + } + }, + } + ) + + request = MockRequest("http://localhost", "get", "/test") + result = spec.validate_request(request) + + assert result is None + def test_security_not_found(self, request_validator): request = MockRequest( self.host_url, diff --git a/tests/integration/validation/test_response_validators.py b/tests/integration/validation/test_response_validators.py index dcc1c0a3..ea5c93d7 100644 --- a/tests/integration/validation/test_response_validators.py +++ b/tests/integration/validation/test_response_validators.py @@ -16,6 +16,7 @@ from openapi_core.validation.response.exceptions import InvalidData from openapi_core.validation.response.exceptions import InvalidHeader from openapi_core.validation.response.exceptions import MissingData +from openapi_core.validation.response.exceptions import MissingRequiredHeader from openapi_core.validation.schemas.exceptions import InvalidSchemaValue @@ -135,6 +136,32 @@ def test_invalid_header(self, response_validator): with pytest.warns(DeprecationWarning): response_validator.validate(request, response) + def test_missing_deprecated_required_header(self, response_validator): + request = MockRequest( + self.host_url, + "delete", + "/v1/tags", + path_pattern="/v1/tags", + ) + response_json = { + "data": [ + { + "id": 1, + "name": "Sparky", + "ears": { + "healthy": True, + }, + }, + ], + } + response_data = json.dumps(response_json).encode() + response = MockResponse(response_data) + + with pytest.raises(MissingRequiredHeader) as exc_info: + response_validator.validate(request, response) + + assert exc_info.value == MissingRequiredHeader(name="x-delete-confirm") + def test_valid(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response_json = {