9
9
from openapi_core .schema .schemas .enums import SchemaType , SchemaFormat
10
10
from openapi_core .schema .schemas .exceptions import (
11
11
InvalidSchemaValue , UndefinedSchemaProperty , MissingSchemaProperty ,
12
+ OpenAPISchemaError , NoOneOfSchema , MultipleOneOfSchema ,
12
13
)
13
14
from openapi_core .schema .schemas .util import forcebool
14
15
@@ -27,7 +28,7 @@ class Schema(object):
27
28
def __init__ (
28
29
self , schema_type = None , model = None , properties = None , items = None ,
29
30
schema_format = None , required = None , default = None , nullable = False ,
30
- enum = None , deprecated = False , all_of = None ):
31
+ enum = None , deprecated = False , all_of = None , one_of = None ):
31
32
self .type = schema_type and SchemaType (schema_type )
32
33
self .model = model
33
34
self .properties = properties and dict (properties ) or {}
@@ -39,6 +40,10 @@ def __init__(
39
40
self .enum = enum
40
41
self .deprecated = deprecated
41
42
self .all_of = all_of and list (all_of ) or []
43
+ self .one_of = one_of and list (one_of ) or []
44
+
45
+ self ._all_required_properties_cache = None
46
+ self ._all_optional_properties_cache = None
42
47
43
48
def __getitem__ (self , name ):
44
49
return self .properties [name ]
@@ -52,14 +57,35 @@ def get_all_properties(self):
52
57
53
58
return properties
54
59
60
+ def get_all_properties_names (self ):
61
+ all_properties = self .get_all_properties ()
62
+ return set (all_properties .keys ())
63
+
55
64
def get_all_required_properties (self ):
65
+ if self ._all_required_properties_cache is None :
66
+ self ._all_required_properties_cache = \
67
+ self ._get_all_required_properties ()
68
+
69
+ return self ._all_required_properties_cache
70
+
71
+ def _get_all_required_properties (self ):
72
+ all_properties = self .get_all_properties ()
73
+ required = self .get_all_required_properties_names ()
74
+
75
+ return dict (
76
+ (prop_name , val )
77
+ for prop_name , val in all_properties .items ()
78
+ if prop_name in required
79
+ )
80
+
81
+ def get_all_required_properties_names (self ):
56
82
required = self .required .copy ()
57
83
58
84
for subschema in self .all_of :
59
85
subschema_req = subschema .get_all_required_properties ()
60
86
required += subschema_req
61
87
62
- return required
88
+ return set ( required )
63
89
64
90
def get_cast_mapping (self ):
65
91
mapping = self .DEFAULT_CAST_CALLABLE_GETTER .copy ()
@@ -119,27 +145,58 @@ def _unmarshal_object(self, value):
119
145
raise InvalidSchemaValue (
120
146
"Value of {0} not an object" .format (value ))
121
147
122
- all_properties = self .get_all_properties ()
123
- all_required_properties = self .get_all_required_properties ()
124
- all_properties_keys = all_properties .keys ()
125
- value_keys = value .keys ()
148
+ if self .one_of :
149
+ properties = None
150
+ for one_of_schema in self .one_of :
151
+ try :
152
+ found_props = self ._unmarshal_properties (
153
+ value , one_of_schema )
154
+ except OpenAPISchemaError :
155
+ pass
156
+ else :
157
+ if properties is not None :
158
+ raise MultipleOneOfSchema (
159
+ "Exactly one schema should be valid,"
160
+ "multiple found" )
161
+ properties = found_props
162
+
163
+ if properties is None :
164
+ raise NoOneOfSchema (
165
+ "Exactly one valid schema should be valid, None found." )
166
+
167
+ else :
168
+ properties = self ._unmarshal_properties (value )
169
+
170
+ return ModelFactory ().create (properties , name = self .model )
126
171
127
- extra_props = set (value_keys ) - set (all_properties_keys )
172
+ def _unmarshal_properties (self , value , one_of_schema = None ):
173
+ all_props = self .get_all_properties ()
174
+ all_props_names = self .get_all_properties_names ()
175
+ all_req_props_names = self .get_all_required_properties_names ()
128
176
177
+ if one_of_schema is not None :
178
+ all_props .update (one_of_schema .get_all_properties ())
179
+ all_props_names |= one_of_schema .\
180
+ get_all_properties_names ()
181
+ all_req_props_names |= one_of_schema .\
182
+ get_all_required_properties_names ()
183
+
184
+ value_props_names = value .keys ()
185
+ extra_props = set (value_props_names ) - set (all_props_names )
129
186
if extra_props :
130
187
raise UndefinedSchemaProperty (
131
188
"Undefined properties in schema: {0}" .format (extra_props ))
132
189
133
190
properties = {}
134
- for prop_name , prop in iteritems (all_properties ):
191
+ for prop_name , prop in iteritems (all_props ):
135
192
try :
136
193
prop_value = value [prop_name ]
137
194
except KeyError :
138
- if prop_name in all_required_properties :
195
+ if prop_name in all_req_props_names :
139
196
raise MissingSchemaProperty (
140
197
"Missing schema property {0}" .format (prop_name ))
141
198
if not prop .nullable and not prop .default :
142
199
continue
143
200
prop_value = prop .default
144
201
properties [prop_name ] = prop .unmarshal (prop_value )
145
- return ModelFactory (). create ( properties , name = self . model )
202
+ return properties
0 commit comments