@@ -155,24 +155,42 @@ def get_all_required_properties_names(self):
155
155
156
156
return set (required )
157
157
158
- def get_cast_mapping (self , custom_formatters = None , strict = True ):
158
+ def get_cast_mapping (self , custom_formatters = None , strict = True ,
159
+ require_all_props = False ):
159
160
primitive_unmarshallers = self .get_primitive_unmarshallers (
160
- custom_formatters = custom_formatters )
161
+ custom_formatters = custom_formatters ,
162
+ require_all_props = require_all_props
163
+ )
161
164
162
165
primitive_unmarshallers_partial = dict (
163
- (t , functools .partial (u , type_format = self .format , strict = strict ))
166
+ (t , functools .partial (
167
+ u ,
168
+ type_format = self .format ,
169
+ strict = strict ,
170
+ require_all_props = require_all_props )
171
+ )
164
172
for t , u in primitive_unmarshallers .items ()
165
173
)
166
174
167
- pass_defaults = lambda f : functools .partial (
168
- f , custom_formatters = custom_formatters , strict = strict )
175
+ complex_unmarshallers = {
176
+ SchemaType .ANY : self ._unmarshal_any ,
177
+ SchemaType .ARRAY : self ._unmarshal_collection ,
178
+ SchemaType .OBJECT : self ._unmarshal_object ,
179
+ }
180
+
181
+ complex_unmarshallers_partial = dict (
182
+ (t , functools .partial (
183
+ u ,
184
+ custom_formatters = custom_formatters ,
185
+ strict = strict ,
186
+ require_all_props = require_all_props )
187
+ )
188
+ for t , u in complex_unmarshallers .items ()
189
+ )
190
+
169
191
mapping = self .DEFAULT_CAST_CALLABLE_GETTER .copy ()
170
192
mapping .update (primitive_unmarshallers_partial )
171
- mapping .update ({
172
- SchemaType .ANY : pass_defaults (self ._unmarshal_any ),
173
- SchemaType .ARRAY : pass_defaults (self ._unmarshal_collection ),
174
- SchemaType .OBJECT : pass_defaults (self ._unmarshal_object ),
175
- })
193
+ mapping .update (complex_unmarshallers_partial )
176
194
177
195
return defaultdict (lambda : lambda x : x , mapping )
178
196
@@ -183,7 +201,8 @@ def are_additional_properties_allowed(self, one_of_schema=None):
183
201
one_of_schema .additional_properties is not False )
184
202
)
185
203
186
- def cast (self , value , custom_formatters = None , strict = True ):
204
+ def cast (self , value , custom_formatters = None , strict = True ,
205
+ require_all_props = False ):
187
206
"""Cast value to schema type"""
188
207
if value is None :
189
208
if not self .nullable :
@@ -195,7 +214,8 @@ def cast(self, value, custom_formatters=None, strict=True):
195
214
"Value {value} not in enum choices: {type}" , value , self .enum )
196
215
197
216
cast_mapping = self .get_cast_mapping (
198
- custom_formatters = custom_formatters , strict = strict )
217
+ custom_formatters = custom_formatters , strict = strict ,
218
+ require_all_props = require_all_props )
199
219
200
220
if self .type is not SchemaType .STRING and value == '' :
201
221
return None
@@ -210,12 +230,14 @@ def cast(self, value, custom_formatters=None, strict=True):
210
230
raise InvalidSchemaValue (
211
231
"Failed to cast value {value} to type {type}" , value , self .type )
212
232
213
- def unmarshal (self , value , custom_formatters = None , strict = True ):
233
+ def unmarshal (self , value , custom_formatters = None , strict = True ,
234
+ require_all_props = False ):
214
235
"""Unmarshal parameter from the value."""
215
236
if self .deprecated :
216
237
warnings .warn ("The schema is deprecated" , DeprecationWarning )
217
238
218
- casted = self .cast (value , custom_formatters = custom_formatters , strict = strict )
239
+ casted = self .cast (value , custom_formatters = custom_formatters , strict = strict ,
240
+ require_all_props = require_all_props )
219
241
220
242
if casted is None and not self .required :
221
243
return None
@@ -242,7 +264,8 @@ def get_primitive_unmarshallers(self, **options):
242
264
243
265
return unmarshallers
244
266
245
- def _unmarshal_any (self , value , custom_formatters = None , strict = True ):
267
+ def _unmarshal_any (self , value , custom_formatters = None , strict = True ,
268
+ require_all_props = False ):
246
269
types_resolve_order = [
247
270
SchemaType .OBJECT , SchemaType .ARRAY , SchemaType .BOOLEAN ,
248
271
SchemaType .INTEGER , SchemaType .NUMBER , SchemaType .STRING ,
@@ -252,7 +275,10 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
252
275
result = None
253
276
for subschema in self .one_of :
254
277
try :
255
- casted = subschema .cast (value , custom_formatters )
278
+ casted = subschema .cast (
279
+ value , custom_formatters ,
280
+ require_all_props = require_all_props
281
+ )
256
282
except (OpenAPISchemaError , TypeError , ValueError ):
257
283
continue
258
284
else :
@@ -277,7 +303,8 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
277
303
278
304
raise NoValidSchema (value )
279
305
280
- def _unmarshal_collection (self , value , custom_formatters = None , strict = True ):
306
+ def _unmarshal_collection (self , value , custom_formatters = None , strict = True ,
307
+ require_all_props = False ):
281
308
if not isinstance (value , (list , tuple )):
282
309
raise InvalidSchemaValue ("Value {value} is not of type {type}" , value , self .type )
283
310
@@ -287,11 +314,13 @@ def _unmarshal_collection(self, value, custom_formatters=None, strict=True):
287
314
f = functools .partial (
288
315
self .items .unmarshal ,
289
316
custom_formatters = custom_formatters , strict = strict ,
317
+ require_all_props = require_all_props
290
318
)
291
319
return list (map (f , value ))
292
320
293
321
def _unmarshal_object (self , value , model_factory = None ,
294
- custom_formatters = None , strict = True ):
322
+ custom_formatters = None , strict = True ,
323
+ require_all_props = False ):
295
324
if not isinstance (value , (dict , )):
296
325
raise InvalidSchemaValue ("Value {value} is not of type {type}" , value , self .type )
297
326
@@ -302,7 +331,8 @@ def _unmarshal_object(self, value, model_factory=None,
302
331
for one_of_schema in self .one_of :
303
332
try :
304
333
found_props = self ._unmarshal_properties (
305
- value , one_of_schema , custom_formatters = custom_formatters )
334
+ value , one_of_schema , custom_formatters = custom_formatters ,
335
+ require_all_props = False )
306
336
except OpenAPISchemaError :
307
337
pass
308
338
else :
@@ -315,12 +345,14 @@ def _unmarshal_object(self, value, model_factory=None,
315
345
316
346
else :
317
347
properties = self ._unmarshal_properties (
318
- value , custom_formatters = custom_formatters )
348
+ value , custom_formatters = custom_formatters ,
349
+ require_all_props = require_all_props )
319
350
320
351
return model_factory .create (properties , name = self .model )
321
352
322
353
def _unmarshal_properties (self , value , one_of_schema = None ,
323
- custom_formatters = None , strict = True ):
354
+ custom_formatters = None , strict = True ,
355
+ require_all_props = False ):
324
356
all_props = self .get_all_properties ()
325
357
all_props_names = self .get_all_properties_names ()
326
358
all_req_props_names = self .get_all_required_properties_names ()
@@ -344,7 +376,10 @@ def _unmarshal_properties(self, value, one_of_schema=None,
344
376
for prop_name in extra_props :
345
377
prop_value = value [prop_name ]
346
378
properties [prop_name ] = self .additional_properties .unmarshal (
347
- prop_value , custom_formatters = custom_formatters )
379
+ prop_value ,
380
+ custom_formatters = custom_formatters ,
381
+ require_all_props = require_all_props
382
+ )
348
383
349
384
for prop_name , prop in iteritems (all_props ):
350
385
try :
@@ -357,12 +392,16 @@ def _unmarshal_properties(self, value, one_of_schema=None,
357
392
prop_value = prop .default
358
393
try :
359
394
properties [prop_name ] = prop .unmarshal (
360
- prop_value , custom_formatters = custom_formatters )
395
+ prop_value ,
396
+ custom_formatters = custom_formatters ,
397
+ require_all_props = require_all_props
398
+ )
361
399
except OpenAPISchemaError as exc :
362
400
raise InvalidSchemaProperty (prop_name , exc )
363
401
364
402
self ._validate_properties (properties , one_of_schema = one_of_schema ,
365
- custom_formatters = custom_formatters )
403
+ custom_formatters = custom_formatters ,
404
+ require_all_props = require_all_props )
366
405
367
406
return properties
368
407
@@ -380,7 +419,8 @@ def default(x, **kw):
380
419
381
420
return defaultdict (lambda : default , mapping )
382
421
383
- def validate (self , value , custom_formatters = None ):
422
+ def validate (self , value , custom_formatters = None ,
423
+ require_all_props = False ):
384
424
if value is None :
385
425
if not self .nullable :
386
426
raise InvalidSchemaValue ("Null value for non-nullable schema of type {type}" , value , self .type )
@@ -396,11 +436,16 @@ def validate(self, value, custom_formatters=None):
396
436
# structure validation
397
437
validator_mapping = self .get_validator_mapping ()
398
438
validator_callable = validator_mapping [self .type ]
399
- validator_callable (value , custom_formatters = custom_formatters )
439
+ validator_callable (
440
+ value ,
441
+ custom_formatters = custom_formatters ,
442
+ require_all_props = False
443
+ )
400
444
401
445
return value
402
446
403
- def _validate_collection (self , value , custom_formatters = None ):
447
+ def _validate_collection (self , value , custom_formatters = None ,
448
+ require_all_props = False ):
404
449
if self .items is None :
405
450
raise UndefinedItemsSchema (self .type )
406
451
@@ -428,10 +473,12 @@ def _validate_collection(self, value, custom_formatters=None):
428
473
raise OpenAPISchemaError ("Value may not contain duplicate items" )
429
474
430
475
f = functools .partial (self .items .validate ,
431
- custom_formatters = custom_formatters )
476
+ custom_formatters = custom_formatters ,
477
+ require_all_props = require_all_props )
432
478
return list (map (f , value ))
433
479
434
- def _validate_number (self , value , custom_formatters = None ):
480
+ def _validate_number (self , value , custom_formatters = None ,
481
+ require_all_props = False ):
435
482
if self .minimum is not None :
436
483
if self .exclusive_minimum and value <= self .minimum :
437
484
raise InvalidSchemaValue (
@@ -453,7 +500,8 @@ def _validate_number(self, value, custom_formatters=None):
453
500
"Value {value} is not a multiple of {type}" ,
454
501
value , self .multiple_of )
455
502
456
- def _validate_string (self , value , custom_formatters = None ):
503
+ def _validate_string (self , value , custom_formatters = None ,
504
+ require_all_props = False ):
457
505
try :
458
506
schema_format = SchemaFormat (self .format )
459
507
except ValueError :
@@ -502,16 +550,19 @@ def _validate_string(self, value, custom_formatters=None):
502
550
503
551
return True
504
552
505
- def _validate_object (self , value , custom_formatters = None ):
553
+ def _validate_object (self , value , custom_formatters = None ,
554
+ require_all_props = False ):
506
555
properties = value .__dict__
507
556
508
557
if self .one_of :
509
558
valid_one_of_schema = None
510
559
for one_of_schema in self .one_of :
511
560
try :
512
561
self ._validate_properties (
513
- properties , one_of_schema ,
514
- custom_formatters = custom_formatters )
562
+ properties , one_of_schema ,
563
+ custom_formatters = custom_formatters ,
564
+ require_all_props = require_all_props
565
+ )
515
566
except OpenAPISchemaError :
516
567
pass
517
568
else :
@@ -523,8 +574,11 @@ def _validate_object(self, value, custom_formatters=None):
523
574
raise NoOneOfSchema (self .type )
524
575
525
576
else :
526
- self ._validate_properties (properties ,
527
- custom_formatters = custom_formatters )
577
+ self ._validate_properties (
578
+ properties ,
579
+ custom_formatters = custom_formatters ,
580
+ require_all_props = require_all_props
581
+ )
528
582
529
583
if self .min_properties is not None :
530
584
if self .min_properties < 0 :
@@ -554,7 +608,8 @@ def _validate_object(self, value, custom_formatters=None):
554
608
return True
555
609
556
610
def _validate_properties (self , value , one_of_schema = None ,
557
- custom_formatters = None ):
611
+ custom_formatters = None ,
612
+ require_all_props = False ):
558
613
all_props = self .get_all_properties ()
559
614
all_props_names = self .get_all_properties_names ()
560
615
all_req_props_names = self .get_all_required_properties_names ()
@@ -577,19 +632,25 @@ def _validate_properties(self, value, one_of_schema=None,
577
632
for prop_name in extra_props :
578
633
prop_value = value [prop_name ]
579
634
self .additional_properties .validate (
580
- prop_value , custom_formatters = custom_formatters )
635
+ prop_value ,
636
+ custom_formatters = custom_formatters ,
637
+ require_all_props = require_all_props
638
+ )
581
639
582
640
for prop_name , prop in iteritems (all_props ):
583
641
try :
584
642
prop_value = value [prop_name ]
585
643
except KeyError :
586
- if prop_name in all_req_props_names :
644
+ if ( prop_name in all_req_props_names ) or require_all_props :
587
645
raise MissingSchemaProperty (prop_name )
588
646
if not prop .nullable and not prop .default :
589
647
continue
590
648
prop_value = prop .default
591
649
try :
592
- prop .validate (prop_value , custom_formatters = custom_formatters )
650
+ prop .validate (prop_value ,
651
+ custom_formatters = custom_formatters ,
652
+ require_all_props = require_all_props
653
+ )
593
654
except OpenAPISchemaError as exc :
594
655
raise InvalidSchemaProperty (prop_name , original_exception = exc )
595
656
0 commit comments