33from typing import TYPE_CHECKING
44from typing import Any
55from typing import Iterable
6+ from typing import Iterator
67from typing import List
78from typing import Optional
89from typing import cast
3132)
3233from openapi_core .unmarshalling .schemas .exceptions import InvalidSchemaValue
3334from openapi_core .unmarshalling .schemas .exceptions import UnmarshalError
35+ from openapi_core .unmarshalling .schemas .exceptions import UnmarshallerError
3436from openapi_core .unmarshalling .schemas .exceptions import ValidateError
3537from openapi_core .unmarshalling .schemas .formatters import Formatter
3638from openapi_core .unmarshalling .schemas .util import format_byte
@@ -61,24 +63,25 @@ def __init__(
6163 ):
6264 self .schema = schema
6365 self .validator = validator
64- self .format = schema .getkey ("format" )
66+ self .schema_format = schema .getkey ("format" )
6567
6668 if formatter is None :
67- if self .format not in self .FORMATTERS :
68- raise FormatterNotFoundError (self .format )
69- self .formatter = self .FORMATTERS [self .format ]
69+ if self .schema_format not in self .FORMATTERS :
70+ raise FormatterNotFoundError (self .schema_format )
71+ self .formatter = self .FORMATTERS [self .schema_format ]
7072 else :
7173 self .formatter = formatter
7274
7375 def __call__ (self , value : Any ) -> Any :
74- if value is None :
75- return
76-
7776 self .validate (value )
7877
78+ # skip unmarshalling for nullable in OpenAPI 3.0
79+ if value is None and self .schema .getkey ("nullable" , False ):
80+ return value
81+
7982 return self .unmarshal (value )
8083
81- def _formatter_validate (self , value : Any ) -> None :
84+ def _validate_format (self , value : Any ) -> None :
8285 result = self .formatter .validate (value )
8386 if not result :
8487 schema_type = self .schema .getkey ("type" , "any" )
@@ -91,11 +94,14 @@ def validate(self, value: Any) -> None:
9194 schema_type = self .schema .getkey ("type" , "any" )
9295 raise InvalidSchemaValue (value , schema_type , schema_errors = errors )
9396
94- def unmarshal (self , value : Any ) -> Any :
97+ def format (self , value : Any ) -> Any :
9598 try :
96- return self .formatter .unmarshal (value )
97- except ValueError as exc :
98- raise InvalidSchemaFormatValue (value , self .format , exc )
99+ return self .formatter .format (value )
100+ except (ValueError , TypeError ) as exc :
101+ raise InvalidSchemaFormatValue (value , self .schema_format , exc )
102+
103+ def unmarshal (self , value : Any ) -> Any :
104+ return self .format (value )
99105
100106
101107class StringUnmarshaller (BaseSchemaUnmarshaller ):
@@ -192,10 +198,8 @@ def items_unmarshaller(self) -> "BaseSchemaUnmarshaller":
192198 items_schema = self .schema .get ("items" , Spec .from_dict ({}))
193199 return self .unmarshallers_factory .create (items_schema )
194200
195- def __call__ (self , value : Any ) -> Optional [List [Any ]]:
196- value = super ().__call__ (value )
197- if value is None and self .schema .getkey ("nullable" , False ):
198- return None
201+ def unmarshal (self , value : Any ) -> Optional [List [Any ]]:
202+ value = super ().unmarshal (value )
199203 return list (map (self .items_unmarshaller , value ))
200204
201205
@@ -210,38 +214,31 @@ def object_class_factory(self) -> ModelPathFactory:
210214 return ModelPathFactory ()
211215
212216 def unmarshal (self , value : Any ) -> Any :
213- properties = self .unmarshal_raw (value )
217+ properties = self .format (value )
214218
215219 fields : Iterable [str ] = properties and properties .keys () or []
216220 object_class = self .object_class_factory .create (self .schema , fields )
217221
218222 return object_class (** properties )
219223
220- def unmarshal_raw (self , value : Any ) -> Any :
221- try :
222- value = self .formatter .unmarshal (value )
223- except ValueError as exc :
224- schema_format = self .schema .getkey ("format" )
225- raise InvalidSchemaFormatValue (value , schema_format , exc )
226- else :
227- return self ._unmarshal_object (value )
224+ def format (self , value : Any ) -> Any :
225+ formatted = super ().format (value )
226+ return self ._unmarshal_properties (formatted )
228227
229228 def _clone (self , schema : Spec ) -> "ObjectUnmarshaller" :
230229 return cast (
231230 "ObjectUnmarshaller" ,
232231 self .unmarshallers_factory .create (schema , "object" ),
233232 )
234233
235- def _unmarshal_object (self , value : Any ) -> Any :
234+ def _unmarshal_properties (self , value : Any ) -> Any :
236235 properties = {}
237236
238237 if "oneOf" in self .schema :
239238 one_of_properties = None
240239 for one_of_schema in self .schema / "oneOf" :
241240 try :
242- unmarshalled = self ._clone (one_of_schema ).unmarshal_raw (
243- value
244- )
241+ unmarshalled = self ._clone (one_of_schema ).format (value )
245242 except (UnmarshalError , ValueError ):
246243 pass
247244 else :
@@ -259,9 +256,7 @@ def _unmarshal_object(self, value: Any) -> Any:
259256 any_of_properties = None
260257 for any_of_schema in self .schema / "anyOf" :
261258 try :
262- unmarshalled = self ._clone (any_of_schema ).unmarshal_raw (
263- value
264- )
259+ unmarshalled = self ._clone (any_of_schema ).format (value )
265260 except (UnmarshalError , ValueError ):
266261 pass
267262 else :
@@ -319,21 +314,36 @@ def types_unmarshallers(self) -> List["BaseSchemaUnmarshaller"]:
319314 unmarshaller = partial (self .unmarshallers_factory .create , self .schema )
320315 return list (map (unmarshaller , types ))
321316
322- def unmarshal (self , value : Any ) -> Any :
323- for unmarshaller in self .types_unmarshallers :
317+ @property
318+ def type (self ) -> List [str ]:
319+ types = self .schema .getkey ("type" , ["any" ])
320+ assert isinstance (types , list )
321+ return types
322+
323+ def _get_unmarshallers_iter (self ) -> Iterator ["BaseSchemaUnmarshaller" ]:
324+ for schema_type in self .type :
325+ yield self .unmarshallers_factory .create (
326+ self .schema , type_override = schema_type
327+ )
328+
329+ def _get_best_unmarshaller (self , value : Any ) -> "BaseSchemaUnmarshaller" :
330+ for unmarshaller in self ._get_unmarshallers_iter ():
324331 # validate with validator of formatter (usualy type validator)
325332 try :
326- unmarshaller ._formatter_validate (value )
333+ unmarshaller ._validate_format (value )
327334 except ValidateError :
328335 continue
329336 else :
330- return unmarshaller ( value )
337+ return unmarshaller
331338
332- log .warning ("failed to unmarshal multi type" )
333- return value
339+ raise UnmarshallerError ("Unmarshaller not found for type(s)" )
340+
341+ def unmarshal (self , value : Any ) -> Any :
342+ unmarshaller = self ._get_best_unmarshaller (value )
343+ return unmarshaller (value )
334344
335345
336- class AnyUnmarshaller (ComplexUnmarshaller ):
346+ class AnyUnmarshaller (MultiTypeUnmarshaller ):
337347
338348 SCHEMA_TYPES_ORDER = [
339349 "object" ,
@@ -344,6 +354,10 @@ class AnyUnmarshaller(ComplexUnmarshaller):
344354 "string" ,
345355 ]
346356
357+ @property
358+ def type (self ) -> List [str ]:
359+ return self .SCHEMA_TYPES_ORDER
360+
347361 def unmarshal (self , value : Any ) -> Any :
348362 one_of_schema = self ._get_one_of_schema (value )
349363 if one_of_schema :
@@ -357,20 +371,7 @@ def unmarshal(self, value: Any) -> Any:
357371 if all_of_schema :
358372 return self .unmarshallers_factory .create (all_of_schema )(value )
359373
360- for schema_type in self .SCHEMA_TYPES_ORDER :
361- unmarshaller = self .unmarshallers_factory .create (
362- self .schema , type_override = schema_type
363- )
364- # validate with validator of formatter (usualy type validator)
365- try :
366- unmarshaller ._formatter_validate (value )
367- except ValidateError :
368- continue
369- else :
370- return unmarshaller (value )
371-
372- log .warning ("failed to unmarshal any type" )
373- return value
374+ return super ().unmarshal (value )
374375
375376 def _get_one_of_schema (self , value : Any ) -> Optional [Spec ]:
376377 if "oneOf" not in self .schema :
0 commit comments