diff --git a/openapi_core/casting/schemas/casters.py b/openapi_core/casting/schemas/casters.py index 6bbb3374..76737ab0 100644 --- a/openapi_core/casting/schemas/casters.py +++ b/openapi_core/casting/schemas/casters.py @@ -11,6 +11,8 @@ from openapi_core.casting.schemas.exceptions import CastError from openapi_core.schema.schemas import get_properties +from openapi_core.util import BOOLEAN_FALSE_VALUES +from openapi_core.util import BOOLEAN_TRUE_VALUES from openapi_core.util import forcebool from openapi_core.validation.schemas.validators import SchemaValidator @@ -65,7 +67,7 @@ def validate(self, value: Any) -> None: if isinstance(value, bool): return - if value.lower() not in ["false", "true"]: + if value.lower() not in BOOLEAN_TRUE_VALUES + BOOLEAN_FALSE_VALUES: raise ValueError("not a boolean format") def cast(self, value: Union[str, bytes]) -> bool: diff --git a/openapi_core/util.py b/openapi_core/util.py index d8c5da16..029b3602 100644 --- a/openapi_core/util.py +++ b/openapi_core/util.py @@ -4,13 +4,16 @@ from typing import Any from typing import Iterable +BOOLEAN_TRUE_VALUES = ("y", "yes", "t", "true", "on", "1") +BOOLEAN_FALSE_VALUES = ("n", "no", "f", "false", "off", "0") + def forcebool(val: Any) -> bool: if isinstance(val, str): val = val.lower() - if val in ("y", "yes", "t", "true", "on", "1"): + if val in BOOLEAN_TRUE_VALUES: return True - elif val in ("n", "no", "f", "false", "off", "0"): + elif val in BOOLEAN_FALSE_VALUES: return False else: raise ValueError(f"invalid truth value {val!r}") diff --git a/tests/integration/data/v3.0/petstore.yaml b/tests/integration/data/v3.0/petstore.yaml index 735fd96c..e0ea394f 100644 --- a/tests/integration/data/v3.0/petstore.yaml +++ b/tests/integration/data/v3.0/petstore.yaml @@ -286,6 +286,12 @@ paths: operationId: deleteTag tags: - tags + parameters: + - name: x-delete-force + in: header + schema: + type: boolean + required: false requestBody: required: false content: diff --git a/tests/integration/test_petstore.py b/tests/integration/test_petstore.py index fc59d3a8..11bfa250 100644 --- a/tests/integration/test_petstore.py +++ b/tests/integration/test_petstore.py @@ -2091,6 +2091,51 @@ def test_delete_tags_no_requestbody(self, spec): assert result.body is None + @pytest.mark.parametrize( + "header_value,expexted_value", + [ + ("y", True), + ("t", True), + ("yes", True), + ("on", True), + ("true", True), + ("1", True), + ("n", False), + ("f", False), + ("no", False), + ("off", False), + ("false", False), + ("0", False), + ], + ) + def test_delete_tags_header(self, spec, header_value, expexted_value): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" + headers = { + "x-delete-force": header_value, + } + request = MockRequest( + host_url, + "DELETE", + "/tags", + headers=headers, + path_pattern=path_pattern, + ) + + validate_request(request, spec=spec) + + result = unmarshal_request( + request, + spec=spec, + cls=V30RequestParametersUnmarshaller, + ) + + assert result.parameters == Parameters( + header={ + "x-delete-force": expexted_value, + }, + ) + def test_delete_tags_raises_missing_required_response_header( self, spec, response_unmarshaller ):