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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 25 additions & 1 deletion
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

Lines changed: 37 additions & 2 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy