1616 InvalidSchemaValue , UndefinedSchemaProperty , MissingSchemaProperty ,
1717 OpenAPISchemaError , NoOneOfSchema , MultipleOneOfSchema , NoValidSchema ,
1818 UndefinedItemsSchema , InvalidCustomFormatSchemaValue , InvalidSchemaProperty ,
19+ UnmarshallerStrictTypeError ,
1920)
2021from openapi_core .schema .schemas .util import (
2122 forcebool , format_date , format_datetime , format_byte , format_uuid ,
@@ -155,14 +156,19 @@ def get_all_required_properties_names(self):
155156 return set (required )
156157
157158 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+
158167 pass_defaults = lambda f : functools .partial (
159168 f , custom_formatters = custom_formatters , strict = strict )
160169 mapping = self .DEFAULT_CAST_CALLABLE_GETTER .copy ()
170+ mapping .update (primitive_unmarshallers_partial )
161171 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 ),
166172 SchemaType .ANY : pass_defaults (self ._unmarshal_any ),
167173 SchemaType .ARRAY : pass_defaults (self ._unmarshal_collection ),
168174 SchemaType .OBJECT : pass_defaults (self ._unmarshal_object ),
@@ -184,6 +190,10 @@ def cast(self, value, custom_formatters=None, strict=True):
184190 raise InvalidSchemaValue ("Null value for non-nullable schema" , value , self .type )
185191 return self .default
186192
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+
187197 cast_mapping = self .get_cast_mapping (
188198 custom_formatters = custom_formatters , strict = strict )
189199
@@ -193,6 +203,9 @@ def cast(self, value, custom_formatters=None, strict=True):
193203 cast_callable = cast_mapping [self .type ]
194204 try :
195205 return cast_callable (value )
206+ except UnmarshallerStrictTypeError :
207+ raise InvalidSchemaValue (
208+ "Value {value} is not of type {type}" , value , self .type )
196209 except ValueError :
197210 raise InvalidSchemaValue (
198211 "Failed to cast value {value} to type {type}" , value , self .type )
@@ -207,72 +220,27 @@ def unmarshal(self, value, custom_formatters=None, strict=True):
207220 if casted is None and not self .required :
208221 return None
209222
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-
214223 return casted
215224
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+ )
264230
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+ }
270237
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+ )
274242
275- return forcebool ( value )
243+ return unmarshallers
276244
277245 def _unmarshal_any (self , value , custom_formatters = None , strict = True ):
278246 types_resolve_order = [
@@ -301,6 +269,8 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
301269 cast_callable = cast_mapping [schema_type ]
302270 try :
303271 return cast_callable (value )
272+ except UnmarshallerStrictTypeError :
273+ continue
304274 # @todo: remove ValueError when validation separated
305275 except (OpenAPISchemaError , TypeError , ValueError ):
306276 continue
0 commit comments