Reputation: 326
Consider the following schema
schema = {
"value_type":{
"type": "string", "required": True
},
"units": {
"type": "string",
"dependencies": {"value_type": ["float", "integer"]},
"required": True
}
}
I want the units
field to be required only when the value of value_type
field is either float
or integer
.
Here's the behaviour I aim to achieve
v = Validator(schema)
v.validate({"value_type": "float", "units": "mm"}) # 1.
True
v.validate({"value_type": "boolean", "units": "mm"}) # 2.
False
v.validate({"value_type": "float"}) # 3.
False
v.validate({"value_type": "boolean"}) # 4.
True
The above Schema returns the expected result only for the first 3 cases.
If I change the definition of units
(by omitting the "required": True
) to
"units": {"type": "string", "dependencies": {"value_type": ["float", "integer"]}}
then the validation of
v.validate({"value_type": "float"}) # 3.
True
returns True
which is not what I want.
I took a look at oneof
rules in the documentation but couldn't find a way to apply this only to the required
property.
I want the value of required to be True
only when the dependency is met.
How should I modify my schema to achieve this?
Upvotes: 4
Views: 1407
Reputation: 3968
As your variations span more than one field, the *of
rules aren't exactly suited, especially since these seem to be top-level fields in the document.
I would generally advise that there's still Python and not everything must be expressed with a schema, so you can simply define two valid schemas and test against these:
schema1 = {...}
schema2 = {...}
if not any(validator(document, schema=x) for x in (schema1, schema2)):
boom()
This is also better comprehendable than any schema you would end up with.
Alternatively, you could use the check_with
rule. The example shows two different ways to submit an error, where the latter one is prefable when the errors are only presented to humans, as they allow custom messages for different situations while lacking structural information about the error:
class MyValidator(Validator):
def _check_with_units_required(self, field, value):
if value in ("float", "integer"):
if "units" not in self.document:
self._error("units", errors.REQUIRED_FIELD, "check_with")
else:
if "units" in self.document:
self._error(
"units", "The 'units' field must not be provided for value "
"types other than float or integer."
)
schema = {
"value_type": {
"check_with": "units_required",
"required": True,
"type": "string"
},
"units": {
"type": "string",
}
}
validator = MyValidator(schema)
assert validator({"value_type": "float", "units": "mm"})
assert not validator({"value_type": "boolean", "units": "mm"})
assert not validator({"value_type": "float"})
assert validator({"value_type": "boolean"})
Upvotes: 3