16
16
InvalidSchemaValue , UndefinedSchemaProperty , MissingSchemaProperty ,
17
17
OpenAPISchemaError , NoOneOfSchema , MultipleOneOfSchema , NoValidSchema ,
18
18
UndefinedItemsSchema , InvalidCustomFormatSchemaValue , InvalidSchemaProperty ,
19
+ UnmarshallerStrictTypeError ,
19
20
)
20
21
from openapi_core .schema .schemas .util import (
21
22
forcebool , format_date , format_datetime , format_byte , format_uuid ,
@@ -155,14 +156,19 @@ def get_all_required_properties_names(self):
155
156
return set (required )
156
157
157
158
def get_cast_mapping (self , custom_formatters = None , strict = True ):
159
+ primitive_unmarshallers = self .get_primitive_unmarshallers (
160
+ custom_formatters = custom_formatters )
161
+
162
+ primitive_unmarshallers_partial = dict (
163
+ (t , functools .partial (u , type_format = self .format , strict = strict ))
164
+ for t , u in primitive_unmarshallers .items ()
165
+ )
166
+
158
167
pass_defaults = lambda f : functools .partial (
159
168
f , custom_formatters = custom_formatters , strict = strict )
160
169
mapping = self .DEFAULT_CAST_CALLABLE_GETTER .copy ()
170
+ mapping .update (primitive_unmarshallers_partial )
161
171
mapping .update ({
162
- SchemaType .STRING : pass_defaults (self ._unmarshal_string ),
163
- SchemaType .BOOLEAN : pass_defaults (self ._unmarshal_boolean ),
164
- SchemaType .INTEGER : pass_defaults (self ._unmarshal_integer ),
165
- SchemaType .NUMBER : pass_defaults (self ._unmarshal_number ),
166
172
SchemaType .ANY : pass_defaults (self ._unmarshal_any ),
167
173
SchemaType .ARRAY : pass_defaults (self ._unmarshal_collection ),
168
174
SchemaType .OBJECT : pass_defaults (self ._unmarshal_object ),
@@ -184,6 +190,10 @@ def cast(self, value, custom_formatters=None, strict=True):
184
190
raise InvalidSchemaValue ("Null value for non-nullable schema" , value , self .type )
185
191
return self .default
186
192
193
+ if self .enum and value not in self .enum :
194
+ raise InvalidSchemaValue (
195
+ "Value {value} not in enum choices: {type}" , value , self .enum )
196
+
187
197
cast_mapping = self .get_cast_mapping (
188
198
custom_formatters = custom_formatters , strict = strict )
189
199
@@ -193,6 +203,9 @@ def cast(self, value, custom_formatters=None, strict=True):
193
203
cast_callable = cast_mapping [self .type ]
194
204
try :
195
205
return cast_callable (value )
206
+ except UnmarshallerStrictTypeError :
207
+ raise InvalidSchemaValue (
208
+ "Value {value} is not of type {type}" , value , self .type )
196
209
except ValueError :
197
210
raise InvalidSchemaValue (
198
211
"Failed to cast value {value} to type {type}" , value , self .type )
@@ -207,72 +220,27 @@ def unmarshal(self, value, custom_formatters=None, strict=True):
207
220
if casted is None and not self .required :
208
221
return None
209
222
210
- if self .enum and casted not in self .enum :
211
- raise InvalidSchemaValue (
212
- "Value {value} not in enum choices: {type}" , value , self .enum )
213
-
214
223
return casted
215
224
216
- def _unmarshal_string (self , value , custom_formatters = None , strict = True ):
217
- if strict and not isinstance (value , (text_type , binary_type )):
218
- raise InvalidSchemaValue ("Value {value} is not of type {type}" , value , self .type )
219
-
220
- try :
221
- schema_format = SchemaFormat (self .format )
222
- except ValueError :
223
- msg = "Unsupported format {type} unmarshalling for value {value}"
224
- if custom_formatters is not None :
225
- formatstring = custom_formatters .get (self .format )
226
- if formatstring is None :
227
- raise InvalidSchemaValue (msg , value , self .format )
228
- else :
229
- raise InvalidSchemaValue (msg , value , self .format )
230
- 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 )
234
- formatstring = self .STRING_FORMAT_CALLABLE_GETTER [schema_format ]
235
-
236
- try :
237
- return formatstring .unmarshal (value )
238
- except ValueError as exc :
239
- raise InvalidCustomFormatSchemaValue (
240
- "Failed to format value {value} to format {type}: {exception}" , value , self .format , exc )
241
-
242
- def _unmarshal_integer (self , value , custom_formatters = None , strict = True ):
243
- if strict and not isinstance (value , integer_types ):
244
- raise InvalidSchemaValue ("Value {value} is not of type {type}" , value , self .type )
245
-
246
- return int (value )
247
-
248
- def _unmarshal_number (self , value , custom_formatters = None , strict = True ):
249
- if strict and not isinstance (value , (float , ) + integer_types ):
250
- raise InvalidSchemaValue ("Value {value} is not of type {type}" , value , self .type )
251
-
252
- try :
253
- schema_format = SchemaFormat (self .format )
254
- except ValueError :
255
- msg = "Unsupported format {type} unmarshalling for value {value}"
256
- if custom_formatters is not None :
257
- formatnumber = custom_formatters .get (self .format )
258
- if formatnumber is None :
259
- raise InvalidSchemaValue (msg , value , self .format )
260
- else :
261
- raise InvalidSchemaValue (msg , value , self .format )
262
- else :
263
- formatnumber = self .NUMBER_FORMAT_CALLABLE_GETTER [schema_format ]
225
+ def get_primitive_unmarshallers (self , ** options ):
226
+ from openapi_core .schema .schemas .unmarshallers import (
227
+ StringUnmarshaller , BooleanUnmarshaller , IntegerUnmarshaller ,
228
+ NumberUnmarshaller ,
229
+ )
264
230
265
- try :
266
- return formatnumber .unmarshal (value )
267
- except ValueError as exc :
268
- raise InvalidCustomFormatSchemaValue (
269
- "Failed to format value {value} to format {type}: {exception}" , value , self .format , exc )
231
+ unmarshallers_classes = {
232
+ SchemaType .STRING : StringUnmarshaller ,
233
+ SchemaType .BOOLEAN : BooleanUnmarshaller ,
234
+ SchemaType .INTEGER : IntegerUnmarshaller ,
235
+ SchemaType .NUMBER : NumberUnmarshaller ,
236
+ }
270
237
271
- def _unmarshal_boolean (self , value , custom_formatters = None , strict = True ):
272
- if strict and not isinstance (value , (bool , )):
273
- raise InvalidSchemaValue ("Value {value} is not of type {type}" , value , self .type )
238
+ unmarshallers = dict (
239
+ (t , klass (** options ))
240
+ for t , klass in unmarshallers_classes .items ()
241
+ )
274
242
275
- return forcebool ( value )
243
+ return unmarshallers
276
244
277
245
def _unmarshal_any (self , value , custom_formatters = None , strict = True ):
278
246
types_resolve_order = [
@@ -301,6 +269,8 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
301
269
cast_callable = cast_mapping [schema_type ]
302
270
try :
303
271
return cast_callable (value )
272
+ except UnmarshallerStrictTypeError :
273
+ continue
304
274
# @todo: remove ValueError when validation separated
305
275
except (OpenAPISchemaError , TypeError , ValueError ):
306
276
continue
0 commit comments