Hi 👋 In the last days, I noticed some inconsistent behavior of deep_iterable and deep_mapping. Some of the problems have already been mentioned in other issues (links provided below) but for others it seems there is no open issue yet. Since they are partly related, I thought it would be good to have a single overview of the necessary open fixes:
Lists/tuples of validators
Some of the inner validators accept lists while others still require the explicit use of and_. For consistency, I think all of them should ideally be able to handle lists. For the member_validator, the change has been in implemented in #925, but iterable_validator still struggles with lists. For example, the following piece of code works, but replacing any_ with a list will make it fail:
@define
class A:
x: List[str] = field(
validator=deep_iterable(
member_validator=[instance_of(str), min_len(1)],
iterable_validator=and_(instance_of(list), min_len(1)),
),
)
For deep_mapping, lists/tuples not supported for any of its three arguments.
Typing support
When a list of validators is passed, mypy complains about the type, as already pointed out in #1197. However, when a tuple is used instead, mypy is happy.
Wrong error message
When a validation error in one of the inner validators of deep_iterable or deep_mapping occurs, an exception is thrown but the contained message is wrong. For example, using the above code and calling A(["abc", ""]), you get the following error:
ValueError: Length of 'x' must be => 1: 0
It rightfully complains about the length of the second item in the list, but note that the message refers to attribute name x, which is incorrect, since it's not x that is too short but one of its items.
Optional validators
For deep_iterable, only the iterable_validator is optional, which makes sense because if no member_validator was provided, one should simply use a regular validator in the first place. However, for deep_mapping, both value_validator and key_validator are required. This makes its use unnecessarily complicated in certain situations. For example, validating only dictionary keys requires a rather cumbersome workaround and also results in unnecessary calls of the value_validator:
@define
class B:
x: Dict[str, Any] = field(
validator=deep_mapping(
key_validator=and_(instance_of(str), min_len(1)),
value_validator=lambda *x: None,
)
)
Instead, I guess the user-friendly way would be to check that at least one of them is provided, but not necessarily both.
Hi 👋 In the last days, I noticed some inconsistent behavior of
deep_iterableanddeep_mapping. Some of the problems have already been mentioned in other issues (links provided below) but for others it seems there is no open issue yet. Since they are partly related, I thought it would be good to have a single overview of the necessary open fixes:Lists/tuples of validators
Some of the inner validators accept lists while others still require the explicit use of
and_. For consistency, I think all of them should ideally be able to handle lists. For themember_validator, the change has been in implemented in #925, butiterable_validatorstill struggles with lists. For example, the following piece of code works, but replacingany_with a list will make it fail:For
deep_mapping, lists/tuples not supported for any of its three arguments.Typing support
When a list of validators is passed, mypy complains about the type, as already pointed out in #1197. However, when a tuple is used instead, mypy is happy.
Wrong error message
When a validation error in one of the inner validators of
deep_iterableordeep_mappingoccurs, an exception is thrown but the contained message is wrong. For example, using the above code and callingA(["abc", ""]), you get the following error:It rightfully complains about the length of the second item in the list, but note that the message refers to attribute name
x, which is incorrect, since it's notxthat is too short but one of its items.Optional validators
For
deep_iterable, only theiterable_validatoris optional, which makes sense because if nomember_validatorwas provided, one should simply use a regular validator in the first place. However, fordeep_mapping, bothvalue_validatorandkey_validatorare required. This makes its use unnecessarily complicated in certain situations. For example, validating only dictionary keys requires a rather cumbersome workaround and also results in unnecessary calls of thevalue_validator:Instead, I guess the user-friendly way would be to check that at least one of them is provided, but not necessarily both.