From 97c5b6d962ca185fc43fc37a6334081644feb4b8 Mon Sep 17 00:00:00 2001 From: p1c2u Date: Tue, 3 Mar 2026 10:43:48 +0000 Subject: [PATCH] Fix swapped operation/path order in request-parameters flows --- .../unmarshalling/request/unmarshallers.py | 2 +- openapi_core/validation/request/validators.py | 2 +- .../test_path_item_params_validator.py | 73 +++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/openapi_core/unmarshalling/request/unmarshallers.py b/openapi_core/unmarshalling/request/unmarshallers.py index 011dad81..bd668b71 100644 --- a/openapi_core/unmarshalling/request/unmarshallers.py +++ b/openapi_core/unmarshalling/request/unmarshallers.py @@ -198,7 +198,7 @@ def _unmarshal_parameters( self, request: BaseRequest, operation: SchemaPath, path: SchemaPath ) -> RequestUnmarshalResult: try: - params = self._get_parameters(request.parameters, path, operation) + params = self._get_parameters(request.parameters, operation, path) except ParametersError as exc: params = exc.parameters params_errors = exc.errors diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index 3be5cf6b..77190312 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -135,7 +135,7 @@ def _iter_parameters_errors( self, request: BaseRequest, operation: SchemaPath, path: SchemaPath ) -> Iterator[Exception]: try: - self._get_parameters(request.parameters, path, operation) + self._get_parameters(request.parameters, operation, path) except ParametersError as exc: yield from exc.errors diff --git a/tests/unit/unmarshalling/test_path_item_params_validator.py b/tests/unit/unmarshalling/test_path_item_params_validator.py index c7758913..1dc56a3f 100644 --- a/tests/unit/unmarshalling/test_path_item_params_validator.py +++ b/tests/unit/unmarshalling/test_path_item_params_validator.py @@ -9,8 +9,14 @@ from openapi_core.casting.schemas.exceptions import CastError from openapi_core.datatypes import Parameters from openapi_core.testing import MockRequest +from openapi_core.unmarshalling.request.unmarshallers import ( + V30RequestParametersUnmarshaller, +) from openapi_core.validation.request.exceptions import MissingRequiredParameter from openapi_core.validation.request.exceptions import ParameterValidationError +from openapi_core.validation.request.validators import ( + V30RequestParametersValidator, +) class TestPathItemParamsValidator: @@ -169,3 +175,70 @@ def test_request_object_deep_object_params(self, spec, spec_dict): assert is_dataclass(result.parameters.query["paramObj"]) assert result.parameters.query["paramObj"].count == 2 assert result.parameters.query["paramObj"].name == "John" + + def test_request_override_param_uniqueness_parameters_validator( + self, spec, spec_dict + ): + # add parameter on operation with same name as on path but + # different location + spec_dict["paths"]["/resource"]["get"]["parameters"] = [ + { + # full valid parameter object required + "name": "resId", + "in": "header", + "required": False, + "schema": { + "type": "integer", + }, + } + ] + request = MockRequest("http://example.com", "get", "/resource") + with pytest.raises(MissingRequiredParameter): + validate_request( + request, + spec, + base_url="http://example.com", + cls=V30RequestParametersValidator, + ) + + def test_request_object_deep_object_params_parameters_unmarshaller( + self, spec, spec_dict + ): + # override path parameter on operation + spec_dict["paths"]["/resource"]["parameters"] = [ + { + # full valid parameter object required + "name": "paramObj", + "in": "query", + "required": True, + "schema": { + "x-model": "paramObj", + "type": "object", + "properties": { + "count": {"type": "integer"}, + "name": {"type": "string"}, + }, + }, + "explode": True, + "style": "deepObject", + } + ] + + request = MockRequest( + "http://example.com", + "get", + "/resource", + args={"paramObj[count]": 2, "paramObj[name]": "John"}, + ) + result = unmarshal_request( + request, + spec, + base_url="http://example.com", + cls=V30RequestParametersUnmarshaller, + ) + + assert len(result.errors) == 0 + assert len(result.parameters.query) == 1 + assert is_dataclass(result.parameters.query["paramObj"]) + assert result.parameters.query["paramObj"].count == 2 + assert result.parameters.query["paramObj"].name == "John"