I would like to validate a dict
, where the values adhere to the following rules:
float
or List(float)
float
, the value must be 1List(float)
, each float must be positiveHere's my code and some test assertions, which are working properly:
import cerberus
v = cerberus.Validator()
schema1 = {
"key1": {
"type": ["float", "list"],
"min": 1,
"max": 1,
"schema": {"type": "float", "min": 0},
}
}
document1 = {"key1": 1}
document2 = {"key1": 5}
document3 = {"key1": "5"}
document4 = {"key1": [0.5, 0.3]}
document5 = {"key1": ["0.5", 0.3]}
assert v.validate(document1, schema1)
assert not v.validate(document2, schema1)
assert not v.validate(document3, schema1)
assert v.validate(document4, schema1)
assert not v.validate(document5, schema1)
Now, I have to implement one more condition:
List(float)
, the sum
of float
must equal 1Therefore, I wrote a check_with
function as described in the docs (https://docs.python-cerberus.org/en/stable/validation-rules.html).
from cerberus import Validator
class MyValidator(Validator):
def _check_with_sum_eq_one(self, field, value):
"""Checks if sum equals 1"""
if sum(value) != 1:
self._error(field, f"Sum of '{field}' must exactly equal 1")
The adjusted schema and test documents look like this:
v = MyValidator()
schema2 = {
"key1": {
"type": ["float", "list"],
"min": 1,
"max": 1,
"schema": {"type": "float", "min": 0, "max": 1, "check_with": "sum_eq_one"},
}
}
document1 = {"key1": 1}
document2 = {"key1": 5}
document3 = {"key1": "5"}
document4 = {"key1": [0.5, 0.3]} # error
document5 = {"key1": ["0.5", 0.3]} # error
document6 = {"key1": [0.5, 0.5]} # error
Now, whenever the value is a List(float)
, only the first element of the list
will be injected into my function, leading to an TypeError: 'float' object is not iterable
.
When validating document4
, field
will be int=0
and value=0.5
. So the error message makes sense.
I am wondering, why the whole list is not passed to my function? What am I missing here?
What if you try to catch the error and only continue your function, if the error was occurred? For example like in this manner:
class MyValidator(Validator):
def _check_with_sum_eq_one(self, field, value):
""" Checks whether value is a list and its sum equals 1.0. """
if isinstance(value, list) and sum(value) != 1.0:
self._error(str(value), f"Sum of '{field}' must exactly equal 1")
schema2 = {
"key1": {
"type": ["list", "float"],
"min": 1,
"max": 1,
"schema": {"type": "float", "min": 0, "max": 1},
"check_with": "sum_eq_one",
}
}
v = MyValidator(schema2)
document1 = {"key1": 1}
document2 = {"key1": 5}
document3 = {"key1": "5"}
document4 = {"key1": [0.3, 0.5]} # error
document5 = {"key1": ["0.5", 0.3]} # error
#document6 = {"key1": [0.5, 0.5]} # error
assert v.validate(document1)
assert not v.validate(document2)
assert not v.validate(document3)
assert v.validate(document4)
assert not v.validate(document5)