Skip to content

Commit 0df1d05

Browse files
authored
Merge pull request #133 from crunchr/support-any-type-with-one-of-rb1
Add support for one-of with any type
2 parents 4874851 + a1596ea commit 0df1d05

File tree

3 files changed

+58
-11
lines changed

3 files changed

+58
-11
lines changed

openapi_core/schema/schemas/models.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import attr
33
import functools
44
import logging
5-
from base64 import b64decode, b64encode
65
from collections import defaultdict
76
from datetime import date, datetime
87
from uuid import UUID
@@ -229,6 +228,9 @@ def _unmarshal_string(self, value, custom_formatters=None, strict=True):
229228
else:
230229
raise InvalidSchemaValue(msg, value, self.format)
231230
else:
231+
if self.enum and value not in self.enum:
232+
raise InvalidSchemaValue(
233+
"Value {value} not in enum choices: {type}", value, self.enum)
232234
formatstring = self.STRING_FORMAT_CALLABLE_GETTER[schema_format]
233235

234236
try:
@@ -278,13 +280,30 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
278280
SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING,
279281
]
280282
cast_mapping = self.get_cast_mapping()
281-
for schema_type in types_resolve_order:
282-
cast_callable = cast_mapping[schema_type]
283-
try:
284-
return cast_callable(value)
285-
# @todo: remove ValueError when validation separated
286-
except (OpenAPISchemaError, TypeError, ValueError):
287-
continue
283+
if self.one_of:
284+
result = None
285+
for subschema in self.one_of:
286+
try:
287+
casted = subschema.cast(value, custom_formatters)
288+
except (OpenAPISchemaError, TypeError, ValueError):
289+
continue
290+
else:
291+
if result is not None:
292+
raise MultipleOneOfSchema(self.type)
293+
result = casted
294+
295+
if result is None:
296+
raise NoOneOfSchema(self.type)
297+
298+
return result
299+
else:
300+
for schema_type in types_resolve_order:
301+
cast_callable = cast_mapping[schema_type]
302+
try:
303+
return cast_callable(value)
304+
# @todo: remove ValueError when validation separated
305+
except (OpenAPISchemaError, TypeError, ValueError):
306+
continue
288307

289308
raise NoValidSchema(value)
290309

tests/integration/test_petstore.py

Lines changed: 4 additions & 3 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
@@ -19,7 +20,7 @@
1920
from openapi_core.schema.responses.models import Response
2021
from openapi_core.schema.schemas.enums import SchemaType
2122
from openapi_core.schema.schemas.exceptions import (
22-
NoValidSchema, InvalidSchemaProperty, InvalidSchemaValue,
23+
InvalidSchemaProperty, InvalidSchemaValue,
2324
)
2425
from openapi_core.schema.schemas.models import Schema
2526
from openapi_core.schema.servers.exceptions import InvalidServer
@@ -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
@@ -300,6 +300,33 @@ def test_number_format_double(self):
300300

301301
assert result == 1.2
302302

303+
def test_schema_any_one_of(self):
304+
schema = Schema(one_of=[
305+
Schema('string'),
306+
Schema('array', items=Schema('string')),
307+
])
308+
assert schema.unmarshal(['hello']) == ['hello']
309+
310+
def test_schema_any_one_of_mutiple(self):
311+
schema = Schema(one_of=[
312+
Schema('array', items=Schema('string')),
313+
Schema('array', items=Schema('number')),
314+
])
315+
with pytest.raises(MultipleOneOfSchema):
316+
schema.unmarshal([])
317+
318+
def test_schema_any_one_of_no_valid(self):
319+
schema = Schema(one_of=[
320+
Schema('array', items=Schema('string')),
321+
Schema('array', items=Schema('number')),
322+
])
323+
with pytest.raises(NoOneOfSchema):
324+
schema.unmarshal({})
325+
326+
def test_schema_any(self):
327+
schema = Schema()
328+
assert schema.unmarshal('string') == 'string'
329+
303330

304331
class TestSchemaValidate(object):
305332

0 commit comments

Comments
 (0)