在核心,我想要做的是采取一些看起来像这样未经修饰的验证功能功能:处理函数参数与装饰
def f(k: bool):
def g(n):
# check that n is valid
return n
return g
,使他们看起来像这样装饰验证功能:
@k
def f():
def g(n):
# check that n is valid
return n
return g
的想法在这里在于k
在所有的执行功能的描述相同的功能。
具体而言,这些函数都返回“验证”功能,以便与voluptuous validation framework一起使用。所以f()
类型的所有函数都返回一个函数,稍后由Schema()
执行。 k
实际上是allow_none
,也就是说一个标志确定None
的值是否正确。一个非常简单的例子可能是这个示例使用代码:
x = "Some input value."
y = None
input_validator = Schema(f(allow_none=True))
x = input_validator(x) # succeeds, returning x
y = input_validator(y) # succeeds, returning None
input_validator_no_none = Schema(f(allow_none=False))
x = input_validator(x) # succeeds, returning x
y = input_validator(y) # raises an Invalid
而不改变取样使用代码我试图通过改变未修饰的验证功能,装饰验证函数来达到同样的效果。举一个具体的例子,改变这个:
def valid_identifier(allow_none: bool=True):
min_range = Range(min=1)
validator = Any(All(int, min_range), All(Coerce(int), min_range))
return Any(validator, None) if allow_none else validator
要这样:
@allow_none(default=True)
def valid_identifier():
min_range = Range(min=1)
return Any(All(int, min_range), All(Coerce(int), min_range))
功能来自这两个返回的应该是等价的。
什么我试着写是这样的,利用decorator
库:
from decorator import decorator
@decorator
def allow_none(default: bool=True):
def decorate_validator(wrapped_validator, allow_none: bool=default):
@wraps(wrapped_validator)
def validator_allowing_none(*args, **kwargs):
if allow_none:
return Any(None, wrapped_validator)
else:
return wrapped_validator(*args, **kwargs)
return validator_allowing_none
return decorate_validator
而且我有一个unittest.TestCase
为了测试这是否如期望的那样
@allow_none()
def test_wrapped_func():
return Schema(str)
class TestAllowNone(unittest.TestCase):
def test_allow_none__success(self):
test_string = "blah"
validation_function = test_wrapped_func(allow_none=False)
self.assertEqual(test_string, validation_function(test_string))
self.assertEqual(None, validation_function(None))
但我的测试返回以下失败:
def validate_callable(path, data):
try:
> return schema(data)
E TypeError: test_wrapped_func() takes 0 positional arguments but 1 was given
我试过调试这个,但是无法让调试器实际进入装饰。我怀疑由于命名问题(如this (very lengthy) blog post series中提出的问题),test_wrapped_func
没有正确设置它的参数列表,所以装饰器从未被执行,但它也可能完全是别的。
我尝试了一些其他的变化。通过从@allow_none
删除功能括号:
@allow_none
def test_wrapped_func():
return Schema(str)
我得到一个不同的错误:
> validation_function = test_wrapped_func(allow_none=False)
E TypeError: test_wrapped_func() got an unexpected keyword argument 'allow_none'
跌落@decorator
失败:
> validation_function = test_wrapped_func(allow_none=False)
E TypeError: decorate_validator() missing 1 required positional argument: 'wrapped_validator'
这是有道理的,因为@allow_none
需要一个参数,因此逻辑上需要括号。替换它们会导致原始错误。
装饰师是微妙的,我很明显在这里失去了一些东西。这与currying一个函数类似,但它不是很有效。我错过了应该如何实施?
哇!这工作。我想我甚至明白了为什么这是有效的。谢谢您的帮助! –