@@ -185,6 +185,69 @@ def __init__(
185
185
self .unmarshallers_factory = unmarshallers_factory
186
186
self .context = context
187
187
188
+ def _get_one_of_schema_unmarshaller (
189
+ self ,
190
+ value : Any ,
191
+ type_override : Optional [str ] = None ,
192
+ ) -> Optional [BaseSchemaUnmarshaller ]:
193
+ if "oneOf" not in self .schema :
194
+ return None
195
+
196
+ one_of_schemas = self .schema / "oneOf"
197
+ for subschema in one_of_schemas :
198
+ unmarshaller = self .unmarshallers_factory .create (
199
+ subschema , type_override = type_override
200
+ )
201
+ try :
202
+ unmarshaller .validate (value )
203
+ except ValidateError :
204
+ continue
205
+ else :
206
+ return unmarshaller
207
+ return None
208
+
209
+ def _iter_any_of_schema_unmarshallers (
210
+ self ,
211
+ value : Any ,
212
+ type_override : Optional [str ] = None ,
213
+ ) -> Iterator [BaseSchemaUnmarshaller ]:
214
+ if "anyOf" not in self .schema :
215
+ return
216
+
217
+ any_of_schemas = self .schema / "anyOf"
218
+ for subschema in any_of_schemas :
219
+ unmarshaller = self .unmarshallers_factory .create (
220
+ subschema , type_override = type_override
221
+ )
222
+ try :
223
+ unmarshaller .validate (value )
224
+ except ValidateError :
225
+ continue
226
+ else :
227
+ yield unmarshaller
228
+
229
+ def _iter_all_of_schema_unmarshallers (
230
+ self ,
231
+ value : Any ,
232
+ type_override : Optional [str ] = None ,
233
+ ) -> Iterator [BaseSchemaUnmarshaller ]:
234
+ if "allOf" not in self .schema :
235
+ return
236
+
237
+ all_of_schemas = self .schema / "allOf"
238
+ for subschema in all_of_schemas :
239
+ if "type" not in subschema :
240
+ continue
241
+ unmarshaller = self .unmarshallers_factory .create (
242
+ subschema , type_override = type_override
243
+ )
244
+ try :
245
+ unmarshaller .validate (value )
246
+ except ValidateError :
247
+ continue
248
+ else :
249
+ yield unmarshaller
250
+
188
251
189
252
class ArrayUnmarshaller (ComplexUnmarshaller ):
190
253
@@ -221,52 +284,50 @@ def unmarshal(self, value: Any) -> Any:
221
284
222
285
return object_class (** properties )
223
286
224
- def format (self , value : Any ) -> Any :
287
+ def format (self , value : Any , schema_only : bool = False ) -> Any :
225
288
formatted = super ().format (value )
226
- return self ._unmarshal_properties (formatted )
289
+ return self ._unmarshal_properties (formatted , schema_only = schema_only )
290
+
291
+ def _unmarshal_properties (
292
+ self , value : Any , schema_only : bool = False
293
+ ) -> Any :
294
+ properties = {}
227
295
228
- def _clone (self , schema : Spec ) -> "ObjectUnmarshaller" :
229
- return cast (
230
- "ObjectUnmarshaller" ,
231
- self .unmarshallers_factory .create (schema , "object" ),
296
+ one_of_unmarshaller = cast (
297
+ Optional ["ObjectUnmarshaller" ],
298
+ self ._get_one_of_schema_unmarshaller (
299
+ value , type_override = "object"
300
+ ),
232
301
)
302
+ if one_of_unmarshaller is not None :
303
+ one_of_properties = one_of_unmarshaller .format (
304
+ value , schema_only = True
305
+ )
306
+ properties .update (one_of_properties )
233
307
234
- def _unmarshal_properties (self , value : Any ) -> Any :
235
- properties = {}
308
+ any_of_unmarshallers = cast (
309
+ Iterator ["ObjectUnmarshaller" ],
310
+ self ._iter_any_of_schema_unmarshallers (
311
+ value , type_override = "object"
312
+ ),
313
+ )
314
+ for any_of_unmarshaller in any_of_unmarshallers :
315
+ any_of_properties = any_of_unmarshaller .format (
316
+ value , schema_only = True
317
+ )
318
+ properties .update (any_of_properties )
236
319
237
- if "oneOf" in self .schema :
238
- one_of_properties = None
239
- for one_of_schema in self .schema / "oneOf" :
240
- try :
241
- unmarshalled = self ._clone (one_of_schema ).format (value )
242
- except (UnmarshalError , ValueError ):
243
- pass
244
- else :
245
- if one_of_properties is not None :
246
- log .warning ("multiple valid oneOf schemas found" )
247
- continue
248
- one_of_properties = unmarshalled
249
-
250
- if one_of_properties is None :
251
- log .warning ("valid oneOf schema not found" )
252
- else :
253
- properties .update (one_of_properties )
254
-
255
- elif "anyOf" in self .schema :
256
- any_of_properties = None
257
- for any_of_schema in self .schema / "anyOf" :
258
- try :
259
- unmarshalled = self ._clone (any_of_schema ).format (value )
260
- except (UnmarshalError , ValueError ):
261
- pass
262
- else :
263
- any_of_properties = unmarshalled
264
- break
265
-
266
- if any_of_properties is None :
267
- log .warning ("valid anyOf schema not found" )
268
- else :
269
- properties .update (any_of_properties )
320
+ all_of_unmarshallers = cast (
321
+ Iterator ["ObjectUnmarshaller" ],
322
+ self ._iter_all_of_schema_unmarshallers (
323
+ value , type_override = "object"
324
+ ),
325
+ )
326
+ for all_of_unmarshaller in all_of_unmarshallers :
327
+ all_of_properties = all_of_unmarshaller .format (
328
+ value , schema_only = True
329
+ )
330
+ properties .update (all_of_properties )
270
331
271
332
for prop_name , prop in get_all_properties (self .schema ).items ():
272
333
read_only = prop .getkey ("readOnly" , False )
@@ -286,6 +347,9 @@ def _unmarshal_properties(self, value: Any) -> Any:
286
347
prop_value
287
348
)
288
349
350
+ if schema_only :
351
+ return properties
352
+
289
353
additional_properties = self .schema .getkey (
290
354
"additionalProperties" , True
291
355
)
@@ -359,63 +423,30 @@ def type(self) -> List[str]:
359
423
return self .SCHEMA_TYPES_ORDER
360
424
361
425
def unmarshal (self , value : Any ) -> Any :
362
- one_of_schema = self ._get_one_of_schema (value )
363
- if one_of_schema :
364
- return self .unmarshallers_factory .create (one_of_schema )(value )
426
+ one_of_schema_unmarshaller = self ._get_one_of_schema_unmarshaller (
427
+ value
428
+ )
429
+ if one_of_schema_unmarshaller :
430
+ return one_of_schema_unmarshaller (value )
365
431
366
- any_of_schema = self ._get_any_of_schema (value )
367
- if any_of_schema :
368
- return self .unmarshallers_factory .create (any_of_schema )(value )
432
+ any_of_schema_unmarshallers = self ._iter_any_of_schema_unmarshallers (
433
+ value
434
+ )
435
+ try :
436
+ any_of_schema_unmarshaller = next (any_of_schema_unmarshallers )
437
+ except StopIteration :
438
+ pass
439
+ else :
440
+ return any_of_schema_unmarshaller (value )
369
441
370
- all_of_schema = self ._get_all_of_schema (value )
371
- if all_of_schema :
372
- return self .unmarshallers_factory .create (all_of_schema )(value )
442
+ all_of_schema_unmarshallers = self ._iter_all_of_schema_unmarshallers (
443
+ value
444
+ )
445
+ try :
446
+ all_of_schema_unmarshaller = next (all_of_schema_unmarshallers )
447
+ except StopIteration :
448
+ pass
449
+ else :
450
+ return all_of_schema_unmarshaller (value )
373
451
374
452
return super ().unmarshal (value )
375
-
376
- def _get_one_of_schema (self , value : Any ) -> Optional [Spec ]:
377
- if "oneOf" not in self .schema :
378
- return None
379
-
380
- one_of_schemas = self .schema / "oneOf"
381
- for subschema in one_of_schemas :
382
- unmarshaller = self .unmarshallers_factory .create (subschema )
383
- try :
384
- unmarshaller .validate (value )
385
- except ValidateError :
386
- continue
387
- else :
388
- return subschema
389
- return None
390
-
391
- def _get_any_of_schema (self , value : Any ) -> Optional [Spec ]:
392
- if "anyOf" not in self .schema :
393
- return None
394
-
395
- any_of_schemas = self .schema / "anyOf"
396
- for subschema in any_of_schemas :
397
- unmarshaller = self .unmarshallers_factory .create (subschema )
398
- try :
399
- unmarshaller .validate (value )
400
- except ValidateError :
401
- continue
402
- else :
403
- return subschema
404
- return None
405
-
406
- def _get_all_of_schema (self , value : Any ) -> Optional [Spec ]:
407
- if "allOf" not in self .schema :
408
- return None
409
-
410
- all_of_schemas = self .schema / "allOf"
411
- for subschema in all_of_schemas :
412
- if "type" not in subschema :
413
- continue
414
- unmarshaller = self .unmarshallers_factory .create (subschema )
415
- try :
416
- unmarshaller .validate (value )
417
- except ValidateError :
418
- continue
419
- else :
420
- return subschema
421
- return None
0 commit comments