Python: 地狱犬 check_with 函数
Python: cerberus check_with function
我想验证 dict
,其中值遵循以下规则:
- 值必须是单个
float
或 List(float)
- 如果是单个
float
,则该值必须为1
- 如果是
List(float)
,每个浮点数必须是正数
这是我的代码和一些测试断言,它们工作正常:
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)
现在,我必须再执行一个条件:
- 如果是
List(float)
,float
的 sum
必须等于 1
因此,我按照文档 (https://docs.python-cerberus.org/en/stable/validation-rules.html) 中的描述编写了一个 check_with
函数。
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")
调整后的架构和测试文档如下所示:
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
现在,只要值为 List(float)
,只有 list
的第一个元素会被注入我的函数,从而导致 TypeError: 'float' object is not iterable
.
验证 document4
时,field
将是 int=0
和 value=0.5
。所以错误信息是有道理的。
我想知道,为什么整个列表没有传递给我的函数?我在这里错过了什么?
以下回答正常。但是,在我看来,它过于复杂了。
首先调整schema2
如下:
schema2 = {
"key1": {
"type": ["float", "list"],
"min": 0,
"max": 1,
"check_with": "sum_eq_one"
}
}
接下来,调整_check_with_sum_eq_one
如下:
class MyValidator(Validator):
def _check_with_sum_eq_one(self, field, value):
"""Checks if sum equals 1"""
if (isinstance(value, float) or isinstance(value, int)) and value != 1:
self._error(field, f"Sum of '{field}' must exactly equal 1")
if isinstance(value, list):
if all([isinstance(x, float) for x in value]):
if sum(value) != 1:
self._error(field, f"Sum of '{field}' must exactly equal 1")
else:
self._error(field, f"All list members must be of type ['float']")
最后,断言一切正常。
v = MyValidator()
document1 = {"key1": 1}
document2 = {"key1": 5}
document3 = {"key1": "5"}
document4 = {"key1": [0.5, 0.3]}
document5 = {"key1": ["0.5", 0.3]}
document6 = {"key1": [0.5, 0.5]}
assert v.validate(document1, schema2)
assert not v.validate(document2, schema2)
assert not v.validate(document3, schema2)
assert not v.validate(document4, schema2)
assert not v.validate(document5, schema2)
assert v.validate(document6, schema2)
我不喜欢这里的事实是我需要检查 'manually' 是否所有列表成员都是 float
(if all([isinstance(x, float) for x in value])
) 类型。在我看来,这个测试属于schema2
。但是,我没有成功地以某种方式调整 schema2
,即 float
类型的测试先于 check_with
验证。
任何进一步简化此任务的提示都将不胜感激。
如果您尝试捕获错误并仅在发生错误时继续您的功能怎么办?例如像这样:
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)
我想验证 dict
,其中值遵循以下规则:
- 值必须是单个
float
或List(float)
- 如果是单个
float
,则该值必须为1 - 如果是
List(float)
,每个浮点数必须是正数
这是我的代码和一些测试断言,它们工作正常:
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)
现在,我必须再执行一个条件:
- 如果是
List(float)
,float
的sum
必须等于 1
因此,我按照文档 (https://docs.python-cerberus.org/en/stable/validation-rules.html) 中的描述编写了一个 check_with
函数。
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")
调整后的架构和测试文档如下所示:
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
现在,只要值为 List(float)
,只有 list
的第一个元素会被注入我的函数,从而导致 TypeError: 'float' object is not iterable
.
验证 document4
时,field
将是 int=0
和 value=0.5
。所以错误信息是有道理的。
我想知道,为什么整个列表没有传递给我的函数?我在这里错过了什么?
以下回答正常。但是,在我看来,它过于复杂了。
首先调整schema2
如下:
schema2 = {
"key1": {
"type": ["float", "list"],
"min": 0,
"max": 1,
"check_with": "sum_eq_one"
}
}
接下来,调整_check_with_sum_eq_one
如下:
class MyValidator(Validator):
def _check_with_sum_eq_one(self, field, value):
"""Checks if sum equals 1"""
if (isinstance(value, float) or isinstance(value, int)) and value != 1:
self._error(field, f"Sum of '{field}' must exactly equal 1")
if isinstance(value, list):
if all([isinstance(x, float) for x in value]):
if sum(value) != 1:
self._error(field, f"Sum of '{field}' must exactly equal 1")
else:
self._error(field, f"All list members must be of type ['float']")
最后,断言一切正常。
v = MyValidator()
document1 = {"key1": 1}
document2 = {"key1": 5}
document3 = {"key1": "5"}
document4 = {"key1": [0.5, 0.3]}
document5 = {"key1": ["0.5", 0.3]}
document6 = {"key1": [0.5, 0.5]}
assert v.validate(document1, schema2)
assert not v.validate(document2, schema2)
assert not v.validate(document3, schema2)
assert not v.validate(document4, schema2)
assert not v.validate(document5, schema2)
assert v.validate(document6, schema2)
我不喜欢这里的事实是我需要检查 'manually' 是否所有列表成员都是 float
(if all([isinstance(x, float) for x in value])
) 类型。在我看来,这个测试属于schema2
。但是,我没有成功地以某种方式调整 schema2
,即 float
类型的测试先于 check_with
验证。
任何进一步简化此任务的提示都将不胜感激。
如果您尝试捕获错误并仅在发生错误时继续您的功能怎么办?例如像这样:
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)