Skip to content

Commit b252440

Browse files
authored
Merge pull request #697 from python-openapi/fix/deserializing-media-type-urlencoded-content-type-fix
Deserializing media type urlencoded content type
2 parents 0838a84 + 0cff4cb commit b252440

File tree

3 files changed

+79
-8
lines changed

3 files changed

+79
-8
lines changed

openapi_core/deserializing/media_types/deserializers.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,19 @@ def decode_property(
125125
location: Mapping[str, Any],
126126
) -> Any:
127127
if self.encoding is None or prop_name not in self.encoding:
128+
prop_schema_type = prop_schema.getkey("type", "")
129+
if (
130+
self.mimetype == "application/x-www-form-urlencoded"
131+
and prop_schema_type in ["array", "object"]
132+
):
133+
# default serialization strategy for complex objects
134+
# in the application/x-www-form-urlencoded
135+
return self.decode_property_style(
136+
prop_name,
137+
prop_schema,
138+
location,
139+
SchemaPath.from_dict({"style": "form"}),
140+
)
128141
return self.decode_property_content_type(
129142
prop_name, prop_schema, location
130143
)
@@ -163,20 +176,24 @@ def decode_property_content_type(
163176
prop_name: str,
164177
prop_schema: SchemaPath,
165178
location: Mapping[str, Any],
166-
prep_encoding: Optional[SchemaPath] = None,
179+
prop_encoding: Optional[SchemaPath] = None,
167180
) -> Any:
168-
prop_content_type = get_content_type(prop_schema, prep_encoding)
181+
prop_content_type = get_content_type(prop_schema, prop_encoding)
169182
prop_deserializer = self.evolve(
170183
prop_content_type,
171184
prop_schema,
172185
)
173186
prop_schema_type = prop_schema.getkey("type", "")
174-
if prop_schema_type == "array":
187+
if (
188+
self.mimetype.startswith("multipart")
189+
and prop_schema_type == "array"
190+
):
175191
if isinstance(location, SuportsGetAll):
176192
value = location.getall(prop_name)
193+
return list(map(prop_deserializer.deserialize, value))
177194
if isinstance(location, SuportsGetList):
178195
value = location.getlist(prop_name)
179-
return list(map(prop_deserializer.deserialize, value))
180-
else:
181-
value = location[prop_name]
182-
return prop_deserializer.deserialize(value)
196+
return list(map(prop_deserializer.deserialize, value))
197+
198+
value = location[prop_name]
199+
return prop_deserializer.deserialize(value)

openapi_core/deserializing/media_types/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def xml_loads(value: Union[str, bytes], **parameters: str) -> Element:
4141

4242

4343
def urlencoded_form_loads(value: Any, **parameters: str) -> Mapping[str, Any]:
44-
return dict(parse_qsl(value))
44+
return ImmutableMultiDict(parse_qsl(value))
4545

4646

4747
def data_form_loads(

tests/unit/deserializing/test_media_types_deserializers.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,60 @@ def test_urlencoded_form_simple(self, deserializer_factory):
214214
"name": "foo bar",
215215
}
216216

217+
def test_urlencoded_complex(self, deserializer_factory):
218+
mimetype = "application/x-www-form-urlencoded"
219+
schema_dict = {
220+
"type": "object",
221+
"properties": {
222+
"prop": {
223+
"type": "array",
224+
"items": {
225+
"type": "integer",
226+
},
227+
},
228+
},
229+
}
230+
schema = SchemaPath.from_dict(schema_dict)
231+
deserializer = deserializer_factory(mimetype, schema=schema)
232+
value = "prop=a&prop=b&prop=c"
233+
234+
result = deserializer.deserialize(value)
235+
236+
assert result == {
237+
"prop": ["a", "b", "c"],
238+
}
239+
240+
def test_urlencoded_content_type(self, deserializer_factory):
241+
mimetype = "application/x-www-form-urlencoded"
242+
schema_dict = {
243+
"type": "object",
244+
"properties": {
245+
"prop": {
246+
"type": "array",
247+
"items": {
248+
"type": "integer",
249+
},
250+
},
251+
},
252+
}
253+
schema = SchemaPath.from_dict(schema_dict)
254+
encoding_dict = {
255+
"prop": {
256+
"contentType": "application/json",
257+
},
258+
}
259+
encoding = SchemaPath.from_dict(encoding_dict)
260+
deserializer = deserializer_factory(
261+
mimetype, schema=schema, encoding=encoding
262+
)
263+
value = 'prop=["a","b","c"]'
264+
265+
result = deserializer.deserialize(value)
266+
267+
assert result == {
268+
"prop": ["a", "b", "c"],
269+
}
270+
217271
def test_urlencoded_deepobject(self, deserializer_factory):
218272
mimetype = "application/x-www-form-urlencoded"
219273
schema_dict = {

0 commit comments

Comments
 (0)