目录
- 一、前置说明
- 1、总体目录
- 2、相关回顾
- 3、本节目标
- 二、操作步骤
- 1、项目目录
- 2、代码实现
- 3、测试代码
- 4、日志输出
- 三、后置说明
- 1、要点小结
- 2、下节准备
一、前置说明
1、总体目录
- 《 pyparamvalidate 参数校验器,从编码到发布全过程》
2、相关回顾
- 使用 RaiseExceptionMeta 元类隐式装饰 Validator 类中的所有校验函数
3、本节目标
- 为
validator
对象添加链式调用功能,并return
校验后的值
二、操作步骤
1、项目目录
atme
:@me
用于存放临时的代码片断或其它内容。pyparamvalidate
: 新建一个与项目名称同名的package,为了方便发布至pypi
。core
: 用于存放核心代码。tests
: 用于存放测试代码。utils
: 用于存放一些工具类或方法。
2、代码实现
pyparamvalidate/core/validator.py
import functools
import inspect
def raise_exception(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
bound_args = inspect.signature(func).bind(self, *args, **kwargs).arguments
exception_msg = kwargs.get('exception_msg', None) or bound_args.get('exception_msg', None)
result = func(self, *args, **kwargs)
if not result:
exception_msg = exception_msg or self.field_rule_des
exception_msg = f"'{self.validate_field}' value error: {exception_msg}" if self.validate_field else f"{exception_msg}"
raise ValueError(exception_msg)
# 返回 self , 而不是 result
return self
return wrapper
class RaiseExceptionMeta(type):
def __new__(cls, name, bases, dct):
for key, value in dct.items():
# 如果是静态方法,则将它替换为一个新的静态方法,新的静态方法调用 raise_exception 函数,将原静态方法作为参数传递给raise_exception
if isinstance(value, staticmethod):
dct[key] = staticmethod(raise_exception(value.__func__))
# 如果是类方法,则将它替换为一个新的类方法,新的类方法调用 raise_exception 函数,将原类方法作为参数传递给raise_exception
if isinstance(value, classmethod):
dct[key] = classmethod(raise_exception(value.__func__))
# 如果是普通的成员方法,则将它替换为一个新的函数,新函数调用 raise_exception 函数,将原函数作为参数传递给 raise_exception
# 添加校验逻辑: 排除掉以双下划线 __ 开头的方法, 如 __init__,__new__等
if inspect.isfunction(value) and not key.startswith("__"):
dct[key] = raise_exception(value)
return super().__new__(cls, name, bases, dct)
class Validator(metaclass=RaiseExceptionMeta):
def __init__(self, value, validate_field=None, field_rule_des=None):
self.value = value
self.validate_field = validate_field
self.field_rule_des = field_rule_des
def is_string(self, exception_msg=None):
return isinstance(self.value, str)
def is_not_empty(self, exception_msg=None):
return bool(self.value)
...
if __name__ == '__main__':
result = Validator(value='123', validate_field='TestField',
field_rule_des='value must be a string').is_string().is_not_empty().value
print(result)
try:
result = Validator(value=123, validate_field='TestField',
field_rule_des='value must be a string').is_string().is_not_empty().value
except Exception as e:
print(e)
3、测试代码
使用 if __name__ == '__main__'
中的简易测试代码。
4、日志输出
输出结果,验证通过:
123
'TestField' value error: value must be a string
三、后置说明
1、要点小结
- 通过
return self
实现了链式调用的功能。 - 在
RaiseExceptionMeta
元类中添加if inspect.isfunction(value) and not key.startswith("__")
判断逻辑,避免 raise_exception 装饰器调用__init__
方法 。 - 虽然从功能上实现了链式调用的功能,但是
pycharm
编辑器无法智能识别可链式调用的方法,对调用方不友好。
2、下节准备
- 在校验函数中 return self, 方便调用方使用链式校验。
点击返回主目录