Skip to content

Commit e3da8d3

Browse files
authored
Merge pull request #379 from Yarn-e/feature/deep-object-support
Add deepObject support
2 parents 868c081 + cc42e15 commit e3da8d3

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

openapi_core/deserializing/parameters/factories.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from functools import partial
23
from typing import Dict
34

@@ -25,6 +26,7 @@ class ParameterDeserializersFactory:
2526
"simple": partial(split, separator=","),
2627
"spaceDelimited": partial(split, separator=" "),
2728
"pipeDelimited": partial(split, separator="|"),
29+
"deepObject": partial(re.split, pattern=r"\[|\]"),
2830
}
2931

3032
def create(self, param_or_header: Spec) -> BaseParameterDeserializer:

openapi_core/schema/parameters.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from typing import Any
23
from typing import Dict
34
from typing import Optional
@@ -53,16 +54,39 @@ def get_value(
5354
) -> Any:
5455
"""Returns parameter/header value from specific location"""
5556
name = name or param_or_header["name"]
57+
style = get_style(param_or_header)
5658

5759
if name not in location:
58-
raise KeyError
60+
# Only check if the name is not in the location if the style of
61+
# the param is deepObject,this is because deepObjects will never be found
62+
# as their key also includes the properties of the object already.
63+
if style != "deepObject":
64+
raise KeyError
65+
keys_str = " ".join(location.keys())
66+
if not re.search(rf"{name}\[\w+\]", keys_str):
67+
raise KeyError
5968

6069
aslist = get_aslist(param_or_header)
6170
explode = get_explode(param_or_header)
6271
if aslist and explode:
72+
if style == "deepObject":
73+
return get_deep_object_value(location, name)
6374
if isinstance(location, SuportsGetAll):
6475
return location.getall(name)
6576
if isinstance(location, SuportsGetList):
6677
return location.getlist(name)
6778

6879
return location[name]
80+
81+
82+
def get_deep_object_value(
83+
location: Union[Headers, Dict[str, Any]],
84+
name: Optional[str] = None,
85+
) -> Dict[str, Any]:
86+
values = {}
87+
for key, value in location.items():
88+
# Split the key from the brackets.
89+
key_split = re.split(pattern=r"\[|\]", string=key)
90+
if key_split[0] == name:
91+
values[key_split[1]] = value
92+
return values

tests/integration/validation/test_validators.py

+37-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929

3030
class TestRequestValidator:
31-
3231
host_url = "http://petstore.swagger.io"
3332

3433
api_key = "12345"
@@ -528,9 +527,45 @@ def test_request_override_param_uniqueness(self, spec, spec_dict):
528527
assert result.body is None
529528
assert result.parameters == Parameters()
530529

530+
def test_request_object_deep_object_params(self, spec, spec_dict):
531+
# override path parameter on operation
532+
spec_dict["paths"]["/resource"]["parameters"] = [
533+
{
534+
# full valid parameter object required
535+
"name": "paramObj",
536+
"in": "query",
537+
"required": True,
538+
"schema": {
539+
"type": "object",
540+
"properties": {
541+
"count": {"type": "integer"},
542+
"name": {"type": "string"},
543+
},
544+
},
545+
"explode": True,
546+
"style": "deepObject",
547+
}
548+
]
549+
550+
request = MockRequest(
551+
"http://example.com",
552+
"get",
553+
"/resource",
554+
args={"paramObj[count]": 2, "paramObj[name]": "John"},
555+
)
556+
result = openapi_request_validator.validate(
557+
spec, request, base_url="http://example.com"
558+
)
559+
560+
assert len(result.errors) == 0
561+
assert result.body is None
562+
assert len(result.parameters.query) == 1
563+
assert is_dataclass(result.parameters.query["paramObj"])
564+
assert result.parameters.query["paramObj"].count == 2
565+
assert result.parameters.query["paramObj"].name == "John"
531566

532-
class TestResponseValidator:
533567

568+
class TestResponseValidator:
534569
host_url = "http://petstore.swagger.io"
535570

536571
@pytest.fixture

0 commit comments

Comments
 (0)