Skip to content

Commit 7d903a8

Browse files
Add support for one-of with any type
1 parent 4d99cbe commit 7d903a8

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

openapi_core/schema/schemas/models.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ def _unmarshal_string(self, value, custom_formatters=None, strict=True):
219219
else:
220220
raise InvalidSchemaValue(msg, value, self.format)
221221
else:
222+
if self.enum and value not in self.enum:
223+
raise InvalidSchemaValue(
224+
"Value {value} not in enum choices: {type}", value, self.enum)
222225
formatstring = self.STRING_FORMAT_CALLABLE_GETTER[schema_format]
223226

224227
try:
@@ -251,13 +254,30 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
251254
SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING,
252255
]
253256
cast_mapping = self.get_cast_mapping()
254-
for schema_type in types_resolve_order:
255-
cast_callable = cast_mapping[schema_type]
256-
try:
257-
return cast_callable(value)
258-
# @todo: remove ValueError when validation separated
259-
except (OpenAPISchemaError, TypeError, ValueError):
260-
continue
257+
if self.one_of:
258+
result = None
259+
for subschema in self.one_of:
260+
try:
261+
casted = subschema.cast(value, custom_formatters)
262+
except (OpenAPISchemaError, TypeError, ValueError):
263+
continue
264+
else:
265+
if result is not None:
266+
raise MultipleOneOfSchema(self.type)
267+
result = casted
268+
269+
if result is None:
270+
raise NoOneOfSchema(self.type)
271+
272+
return result
273+
else:
274+
for schema_type in types_resolve_order:
275+
cast_callable = cast_mapping[schema_type]
276+
try:
277+
return cast_callable(value)
278+
# @todo: remove ValueError when validation separated
279+
except (OpenAPISchemaError, TypeError, ValueError):
280+
continue
261281

262282
raise NoValidSchema(value)
263283

tests/integration/test_petstore.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import pytest
3+
from datetime import datetime
34
from base64 import b64encode
45
from uuid import UUID
56
from six import iteritems, text_type
@@ -1213,7 +1214,7 @@ def test_post_tags_created_datetime(
12131214

12141215
assert parameters == {}
12151216
assert isinstance(body, BaseModel)
1216-
assert body.created == created
1217+
assert body.created == datetime(2016, 4, 16, 16, 6, 5)
12171218
assert body.name == pet_name
12181219

12191220
code = 400
@@ -1257,7 +1258,7 @@ def test_post_tags_created_invalid_type(
12571258
)
12581259

12591260
parameters = request.get_parameters(spec)
1260-
with pytest.raises(NoValidSchema):
1261+
with pytest.raises(InvalidMediaTypeValue):
12611262
request.get_body(spec)
12621263

12631264
assert parameters == {}

tests/unit/schema/test_schemas.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,33 @@ def test_number_int_invalid(self):
269269
with pytest.raises(InvalidSchemaValue):
270270
schema.unmarshal(value)
271271

272+
def test_schema_any_one_of(self):
273+
schema = Schema(one_of=[
274+
Schema('string'),
275+
Schema('array', items=Schema('string')),
276+
])
277+
assert schema.unmarshal(['hello']) == ['hello']
278+
279+
def test_schema_any_one_of_mutiple(self):
280+
schema = Schema(one_of=[
281+
Schema('array', items=Schema('string')),
282+
Schema('array', items=Schema('number')),
283+
])
284+
with pytest.raises(MultipleOneOfSchema):
285+
schema.unmarshal([])
286+
287+
def test_schema_any_one_of_no_valid(self):
288+
schema = Schema(one_of=[
289+
Schema('array', items=Schema('string')),
290+
Schema('array', items=Schema('number')),
291+
])
292+
with pytest.raises(NoOneOfSchema):
293+
schema.unmarshal({})
294+
295+
def test_schema_any(self):
296+
schema = Schema()
297+
assert schema.unmarshal('string') == 'string'
298+
272299

273300
class TestSchemaValidate(object):
274301

0 commit comments

Comments
 (0)