@@ -378,9 +378,9 @@ def deep_iterable(member_validator, iterable_validator=None):
378378
379379@attrs (repr = False , slots = True , unsafe_hash = True )
380380class _DeepMapping :
381- key_validator = attrib (validator = is_callable ())
382- value_validator = attrib (validator = is_callable ())
383- mapping_validator = attrib (default = None , validator = optional (is_callable ()))
381+ key_validator = attrib (validator = optional ( is_callable () ))
382+ value_validator = attrib (validator = optional ( is_callable () ))
383+ mapping_validator = attrib (validator = optional (is_callable ()))
384384
385385 def __call__ (self , inst , attr , value ):
386386 """
@@ -390,30 +390,51 @@ def __call__(self, inst, attr, value):
390390 self .mapping_validator (inst , attr , value )
391391
392392 for key in value :
393- self .key_validator (inst , attr , key )
394- self .value_validator (inst , attr , value [key ])
393+ if self .key_validator is not None :
394+ self .key_validator (inst , attr , key )
395+ if self .value_validator is not None :
396+ self .value_validator (inst , attr , value [key ])
395397
396398 def __repr__ (self ):
397399 return f"<deep_mapping validator for objects mapping { self .key_validator !r} to { self .value_validator !r} >"
398400
399401
400- def deep_mapping (key_validator , value_validator , mapping_validator = None ):
402+ def deep_mapping (
403+ key_validator = None , value_validator = None , mapping_validator = None
404+ ):
401405 """
402406 A validator that performs deep validation of a dictionary.
403407
408+ All validators are optional, but at least one of *key_validator* or
409+ *value_validator* must be provided.
410+
404411 Args:
405412 key_validator: Validator to apply to dictionary keys.
406413
407414 value_validator: Validator to apply to dictionary values.
408415
409416 mapping_validator:
410- Validator to apply to top-level mapping attribute (optional) .
417+ Validator to apply to top-level mapping attribute.
411418
412419 .. versionadded:: 19.1.0
413420
421+ .. versionchanged:: 25.4.0
422+ *key_validator* and *value_validator* are now optional, but at least one
423+ of them must be provided.
424+
414425 Raises:
415- TypeError: if any sub-validators fail
426+ TypeError: If any sub-validator fails on validation.
427+
428+ ValueError:
429+ If neither *key_validator* nor *value_validator* is provided on
430+ instantiation.
416431 """
432+ if key_validator is None and value_validator is None :
433+ msg = (
434+ "At least one of key_validator or value_validator must be provided"
435+ )
436+ raise ValueError (msg )
437+
417438 return _DeepMapping (key_validator , value_validator , mapping_validator )
418439
419440
0 commit comments