将 validator 校验器从 ParameterValidator 中抽离出来

目录

  • 一、前置说明
    • 1、总体目录
    • 2、相关回顾
    • 3、本节目标
  • 二、操作步骤
    • 1、项目目录
    • 2、代码实现
    • 3、测试代码
    • 4、日志输出
  • 三、后置说明
    • 1、要点小结
    • 2、下节准备

一、前置说明

1、总体目录

  • 《 pyparamvalidate 参数校验器,从编码到发布全过程》

2、相关回顾

  • pyparamvalidate 重构背景和需求分析

3、本节目标

  • validator 校验器从 ParameterValidator 中抽离出来

二、操作步骤

1、项目目录

  • validator.py : 用于存放抽离出来的 validator 校验函数的代码。
  • test_validator.py :存放测试 validator 校验函数的代码。
  • __init__.py : 将 pyparamvalidate 转为 pythonpackage 包,用于统一管理 import

2、代码实现

pyparamvalidate/core/validator.py

import functools
import inspect
import osfrom pyparamvalidate import DictUtilitydef raise_exception(func):@functools.wraps(func)def wrapper(*args, **kwargs):bound_args = inspect.signature(func).bind(*args, **kwargs).argumentsvalidate_field = kwargs.get('validate_field', None) or bound_args.get('validate_field', None)exception_msg = kwargs.get('exception_msg', None) or bound_args.get('exception_msg', None)result = func(*args, **kwargs)if not result and exception_msg is not None:exception_msg = f"'{validate_field}' value error: {exception_msg}" if validate_field else f"{exception_msg}"raise ValueError(exception_msg)return resultreturn wrapper@raise_exception
def is_string(value, validate_field=None, exception_msg=None):return isinstance(value, str)@raise_exception
def is_string(value, validate_field=None, exception_msg=None):return isinstance(value, str)@raise_exception
def is_int(value, validate_field=None, exception_msg=None):return isinstance(value, int)@raise_exception
def is_positive(value, validate_field=None, exception_msg=None):return value > 0@raise_exception
def is_float(value, validate_field=None, exception_msg=None):return isinstance(value, float)@raise_exception
def is_list(value, validate_field=None, exception_msg=None):return isinstance(value, list)@raise_exception
def is_dict(value, validate_field=None, exception_msg=None):return isinstance(value, dict)@raise_exception
def is_set(value, validate_field=None, exception_msg=None):return isinstance(value, set)@raise_exception
def is_tuple(value, validate_field=None, exception_msg=None):return isinstance(value, tuple)@raise_exception
def is_not_none(value, validate_field=None, exception_msg=None):return value is not None@raise_exception
def is_not_empty(value, validate_field=None, exception_msg=None):return bool(value)@raise_exception
def is_allowed_value(value, allowed_values, validate_field=None, exception_msg=None):return value in allowed_values@raise_exception
def max_length(value, max_length, validate_field=None, exception_msg=None):return len(value) <= max_length@raise_exception
def min_length(value, min_length, validate_field=None, exception_msg=None):return len(value) >= min_length@raise_exception
def is_substring(sub_string, super_string, validate_field=None, exception_msg=None):return sub_string in super_string@raise_exception
def is_subset(subset, superset, validate_field=None, exception_msg=None):return subset.issubset(superset)@raise_exception
def is_sublist(sublist, superlist, validate_field=None, exception_msg=None):return set(sublist).issubset(set(superlist))@raise_exception
def contains_substring(superstring, substring, validate_field=None, exception_msg=None):return substring in superstring@raise_exception
def contains_subset(superset, subset, validate_field=None, exception_msg=None):return subset.issubset(superset)@raise_exception
def contains_sublist(superlist, sublist, validate_field=None, exception_msg=None):return set(sublist).issubset(set(superlist))@raise_exception
def is_file_suffix(path, file_suffix, validate_field=None, exception_msg=None):return path.endswith(file_suffix)@raise_exception
def is_file(path, validate_field=None, exception_msg=None):return os.path.isfile(path)@raise_exception
def is_dir(path, validate_field=None, exception_msg=None):return os.path.isdir(path)@raise_exception
def is_similar_dict(target_dict, reference_dict, validate_field=None, exception_msg=None, ignore_keys_whitespace=True):dict_util = DictUtility()return dict_util.is_similar_dict(target_dict, reference_dict, ignore_keys_whitespace)@raise_exception
def is_method(value, validate_field=None, exception_msg=None):return callable(value)

3、测试代码

pyparamvalidate/tests/test_validator.py

import pytestfrom atme.demo_v2.validator_v1 import *def test_is_string():assert is_string(value="test", validate_field='value', exception_msg='value must be string')with pytest.raises(ValueError) as exc_info:is_string(value=123, validate_field='value', exception_msg='value must be string')assert "value must be string" in str(exc_info.value)def test_is_int():assert is_int(value=42, validate_field='value', exception_msg='value must be integer')with pytest.raises(ValueError) as exc_info:is_int(value="test", validate_field='value', exception_msg='value must be integer')assert "value must be integer" in str(exc_info.value)def test_is_positive():assert is_positive(value=42, validate_field='value', exception_msg='value must be positive')with pytest.raises(ValueError) as exc_info:is_positive(value=-1, validate_field='value', exception_msg='value must be positive')assert "value must be positive" in str(exc_info.value)def test_is_float():assert is_float(value=3.14, validate_field='value', exception_msg='value must be float')with pytest.raises(ValueError) as exc_info:is_float(value="test", validate_field='value', exception_msg='value must be float')assert "value must be float" in str(exc_info.value)def test_is_list():assert is_list(value=[1, 2, 3], validate_field='value', exception_msg='value must be list')with pytest.raises(ValueError) as exc_info:is_list(value="test", validate_field='value', exception_msg='value must be list')assert "value must be list" in str(exc_info.value)def test_is_dict():assert is_dict(value={"key": "value"}, validate_field='value', exception_msg='value must be dict')with pytest.raises(ValueError) as exc_info:is_dict(value=[1, 2, 3], validate_field='value', exception_msg='value must be dict')assert "value must be dict" in str(exc_info.value)def test_is_set():assert is_set(value={1, 2, 3}, validate_field='value', exception_msg='value must be set')with pytest.raises(ValueError) as exc_info:is_set(value=[1, 2, 3], validate_field='value', exception_msg='value must be set')assert "value must be set" in str(exc_info.value)def test_is_tuple():assert is_tuple(value=(1, 2, 3), validate_field='value', exception_msg='value must be tuple')with pytest.raises(ValueError) as exc_info:is_tuple(value=[1, 2, 3], validate_field='value', exception_msg='value must be tuple')assert "value must be tuple" in str(exc_info.value)def test_is_not_none():assert is_not_none(value="test", validate_field='value', exception_msg='value must not be None')with pytest.raises(ValueError) as exc_info:is_not_none(value=None, validate_field='value', exception_msg='value must not be None')assert "value must not be None" in str(exc_info.value)def test_is_not_empty():assert is_not_empty(value="test", validate_field='value', exception_msg='value must not be empty')with pytest.raises(ValueError) as exc_info:is_not_empty(value="", validate_field='value', exception_msg='value must not be empty')assert "value must not be empty" in str(exc_info.value)def test_is_allowed_value():assert is_allowed_value(value=3, allowed_values=[1, 2, 3, 4, 5], validate_field='value', exception_msg='value must be in allowed_values')with pytest.raises(ValueError) as exc_info:is_allowed_value(value=6, allowed_values=[1, 2, 3, 4, 5], validate_field='value', exception_msg='value must be in allowed_values')assert "value must be in allowed_values" in str(exc_info.value)def test_max_length():assert max_length(value="test", max_length=5, validate_field='value', exception_msg='value length must be less than or equal to 5')with pytest.raises(ValueError) as exc_info:max_length(value="test", max_length=3, validate_field='value', exception_msg='value length must be less than or equal to 3')assert "value length must be less than or equal to 3" in str(exc_info.value)def test_min_length():assert min_length(value="test", min_length=3, validate_field='value', exception_msg='value length must be greater than or equal to 3')with pytest.raises(ValueError) as exc_info:min_length(value="test", min_length=5, validate_field='value', exception_msg='value length must be greater than or equal to 5')assert "value length must be greater than or equal to 5" in str(exc_info.value)def test_is_substring():assert is_substring(sub_string="st", super_string="test", validate_field='sub_string', exception_msg='sub_string must be a substring of super_string')with pytest.raises(ValueError) as exc_info:is_substring(sub_string="abc", super_string="test", validate_field='sub_string', exception_msg='sub_string must be a substring of super_string')assert "sub_string must be a substring of super_string" in str(exc_info.value)def test_is_subset():assert is_subset(subset={1, 2}, superset={1, 2, 3, 4}, validate_field='subset', exception_msg='subset must be a subset of superset')with pytest.raises(ValueError) as exc_info:is_subset(subset={5, 6}, superset={1, 2, 3, 4}, validate_field='subset', exception_msg='subset must be a subset of superset')assert "subset must be a subset of superset" in str(exc_info.value)def test_is_sublist():assert is_sublist(sublist=[1, 2], superlist=[1, 2, 3, 4], validate_field='sublist', exception_msg='sublist must be a sublist of superlist')with pytest.raises(ValueError) as exc_info:is_sublist(sublist=[5, 6], superlist=[1, 2, 3, 4], validate_field='sublist', exception_msg='sublist must be a sublist of superlist')assert "sublist must be a sublist of superlist" in str(exc_info.value)def test_contains_substring():assert contains_substring(superstring="test", substring="es", validate_field='superstring', exception_msg='superstring must contain substring')with pytest.raises(ValueError) as exc_info:contains_substring(superstring="test", substring="abc", validate_field='superstring', exception_msg='superstring must contain substring')assert "superstring must contain substring" in str(exc_info.value)def test_contains_subset():assert contains_subset(superset={1, 2, 3, 4}, subset={1, 2}, validate_field='superset', exception_msg='superset must contain subset')with pytest.raises(ValueError) as exc_info:contains_subset(superset={1, 2, 3, 4}, subset={5, 6}, validate_field='superset', exception_msg='superset must contain subset')assert "superset must contain subset" in str(exc_info.value)def test_contains_sublist():assert contains_sublist(superlist=[1, 2, 3, 4], sublist=[1, 2], validate_field='superlist', exception_msg='superlist must contain sublist')with pytest.raises(ValueError) as exc_info:contains_sublist(superlist=[1, 2, 3, 4], sublist=[5, 6], validate_field='superlist', exception_msg='superlist must contain sublist')assert "superlist must contain sublist" in str(exc_info.value)def test_is_file_suffix():assert is_file_suffix(path="example.txt", file_suffix=".txt", validate_field='path', exception_msg='path must have the specified file suffix')with pytest.raises(ValueError) as exc_info:is_file_suffix(path="example.txt", file_suffix=".csv", validate_field='path', exception_msg='path must have the specified file suffix')assert "path must have the specified file suffix" in str(exc_info.value)def test_is_file():assert is_file(path=__file__, validate_field='path', exception_msg='path must be an existing file')with pytest.raises(ValueError) as exc_info:is_file(path="nonexistent_file.txt", validate_field='path', exception_msg='path must be an existing file')assert "path must be an existing file" in str(exc_info.value)def test_is_dir():assert is_dir(path=os.path.dirname(__file__), validate_field='path', exception_msg='path must be an existing directory')with pytest.raises(ValueError) as exc_info:is_dir(path="nonexistent_directory", validate_field='path', exception_msg='path must be an existing directory')assert "path must be an existing directory" in str(exc_info.value)def test_is_similar_dict():dict1 = {"key1": "value1", "key2": "value2"}dict2 = {"key1": "value2", "key2": "value3"}assert is_similar_dict(target_dict=dict1, reference_dict=dict2, validate_field='target_dict', exception_msg='target_dict must be similar to reference_dict')dict3 = {"key2": "value1", "key3": "value3"}with pytest.raises(ValueError) as exc_info:is_similar_dict(target_dict=dict1, reference_dict=dict3, validate_field='target_dict', exception_msg='target_dict must be similar to reference_dict')assert "target_dict must be similar to reference_dict" in str(exc_info.value)def test_is_method():assert is_method(value=print, validate_field='value', exception_msg='value must be a callable method')with pytest.raises(ValueError) as exc_info:is_method(value="test", validate_field='value', exception_msg='value must be a callable method')assert "value must be a callable method" in str(exc_info.value)

4、日志输出

执行 test 的日志如下,验证通过:

============================= test session starts =============================
collecting ... collected 24 itemstest_validator.py::test_is_string PASSED                                 [  4%]
test_validator.py::test_is_int PASSED                                    [  8%]
test_validator.py::test_is_positive PASSED                               [ 12%]
test_validator.py::test_is_float PASSED                                  [ 16%]
test_validator.py::test_is_list PASSED                                   [ 20%]
test_validator.py::test_is_dict PASSED                                   [ 25%]
test_validator.py::test_is_set PASSED                                    [ 29%]
test_validator.py::test_is_tuple PASSED                                  [ 33%]
test_validator.py::test_is_not_none PASSED                               [ 37%]
test_validator.py::test_is_not_empty PASSED                              [ 41%]
test_validator.py::test_is_allowed_value PASSED                          [ 45%]
test_validator.py::test_max_length PASSED                                [ 50%]
test_validator.py::test_min_length PASSED                                [ 54%]
test_validator.py::test_is_substring PASSED                              [ 58%]
test_validator.py::test_is_subset PASSED                                 [ 62%]
test_validator.py::test_is_sublist PASSED                                [ 66%]
test_validator.py::test_contains_substring PASSED                        [ 70%]
test_validator.py::test_contains_subset PASSED                           [ 75%]
test_validator.py::test_contains_sublist PASSED                          [ 79%]
test_validator.py::test_is_file_suffix PASSED                            [ 83%]
test_validator.py::test_is_file PASSED                                   [ 87%]
test_validator.py::test_is_dir PASSED                                    [ 91%]
test_validator.py::test_is_similar_dict PASSED                           [ 95%]
test_validator.py::test_is_method PASSED                                 [100%]============================= 24 passed in 0.04s ==============================

三、后置说明

1、要点小结

  • 校验函数中的关键字参数 validate_field=None, exception_msg=None 虽然没有被直接调用,但它实际在 raise_exception 装饰器中被隐式调用了。
  • 显示优于隐式,不建议用 **kwargs 代替 validate_field=None, exception_msg=None,方便在编辑器 pycharm 中为调用方智能提示参数。
  • 如果校验函数中有多个参数,永远将被校验的参数放在最前面、参照参数放在后面。
    @raise_exception
    def is_sublist(sublist, superlist, validate_field=None, exception_msg=None):return set(sublist).issubset(set(superlist))@raise_exception
    def contains_substring(superstring, substring, validate_field=None, exception_msg=None):return substring in superstring@raise_exception
    def is_similar_dict(target_dict, reference_dict, validate_field=None, exception_msg=None, ignore_keys_whitespace=True):dict_util = DictUtility()return dict_util.is_similar_dict(target_dict, reference_dict, ignore_keys_whitespace)
    
  • 在每一个校验函数上都添加 @raise_exception 装饰器,显得有点累赘,可以继续优化。

2、下节准备

  • 使用 RaiseExceptionMeta 元类隐式装饰 Validator 类中的所有校验函数。

点击返回主目录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/231570.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01、Kafka ------ 下载、安装 ZooKeeper 和 Kafka

目录 Kafka是什么&#xff1f;安装 ZooKeeper下载安装启动 zookeeper 服务器端启动 zookeeper 的命令行客户端工具 安装 Kafka下载安装启动 Kafka 服务器 Kafka是什么&#xff1f; RabbitMQ的性能比ActiveMQ的性能有显著提升。 Kafka的性能比RabbitMQ的性能又有显著提升。 K…

【React系列】react-router

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 认识react-router 1.2. 前端路由原理 前端路由是如何做到URL和内容进行映射呢&#xff1f;监听URL的改变。 UR…

【MySQL】orderby/groupby出现Using filesort根因分析及优化

序 在日常的数据库运维中&#xff0c;我们可能会遇到一些看似难以理解的现象。比如两个SQL查询语句&#xff0c;仅仅在ORDER BY子句上略有不同&#xff0c;却造成了性能的天壤之别——一个飞速完成&#xff0c;一个则让数据库崩溃。今天就让我们围绕这个问题&#xff0c;深入剖…

prometheus grafana linux服务器监控

文章目录 前传node-exporter安装配置promethues监控node节点grafana操作查看监控&#xff1a;外传 前传 prometheus grafana的安装使用&#xff1a;https://nanxiang.blog.csdn.net/article/details/135384541 本文说下监控nginx&#xff0c;prometheus grafana linux 安装配…

(NeRF学习)NeRF复现 win11

目录 一、获取源码二、环境三、准备数据集1.下载数据集方法一&#xff1a;官方命令方法二&#xff1a;官网下载数据集 2.修改配置 四、开始训练1.更改迭代次数2.开始训练方法一&#xff1a;方法二&#xff1a; 3.使用预训练模型 五、NeRF源码学习 一、获取源码 git clone http…

初识MySQL

一、什么是数据库 数据库&#xff08;Database&#xff0c;简称DB&#xff09;&#xff1a;长期存放在计算机内&#xff0c;有组织、可共享的大量数据的集合&#xff0c;是一个数据“仓库”。 数据库的作用&#xff1a; 可以结构化存储大量的数据&#xff0c;方便检索和访问…

kubeadm开快速的搭建一个k8s集群

kubeadm开快速的搭建一个k8s集群 二进制适合大集群&#xff0c;50台以上主机 kubeadm更适合中小企业的业务集群。 master节点 20.0.0.92 docker kubelet kubeadm kubectl flannel node1 20.0.0. 94 docker kubelet kubeadm kubectl flanne node2 20.0.0.03 docker kubelet…

面试题:聊聊 SpringBoot 中的 SPI 机制

文章目录 简介Java SPI实现示例说明实现类1实现类2相关测试 源码分析Spring SPISpring 示例定义接口相关实现 相关测试类输出结果源码分析 总结 简介 SPI(Service Provider Interface)是JDK内置的一种服务提供发现机制&#xff0c;可以用来启用框架扩展和替换组件,主要用于框架…

HTTPS协议详解

目录 前言 一、HTTPS协议 1、加密是什么 2、为什么要加密 二、常见加密方式 1、对称加密 2、非对称加密 三、数据摘要与数据指纹 1、数据摘要 2、数据指纹 四、HTTPS加密策略探究 1、只使用对称加密 2、只使用非对称加密 3、双方都使用非对称加密 4、对称加密非…

开发个小破软件——网址导航,解压就能用

网址导航 网站导航也称链接目录&#xff0c;将网站地址或系统地址分类&#xff0c;以列表、图文等形式呈现&#xff0c;帮助快速找到需要的地址。 应用场景 高效查找&#xff1a;网址导航是很好的入口&#xff0c;通过分类清晰的网站推荐&#xff0c;可以迅速访问网站资源。…

SVN下载安装(服务器与客户端)

1.下载 服务器下载&#xff1a;Download | VisualSVN Server 客户端下载&#xff1a;自行查找 2. 服务器安装 双击执行 运行 下一步 同意下一步 下一步 选中安装目录 3. 客户端安装 双击执行 下一步 4. 服务器创建仓库 5. 服务器创建用户 6. 客户端获取资源 文件夹右键

微服务全链路灰度方案介绍

目录 一、单体架构下的服务发布 1.1 蓝绿发布 二、微服务架构下的服务发布 三、微服务场景下服务发布的问题 四、全链路灰度解决方案 4.1 物理环境隔离 4.2 逻辑环境隔离 4.3 全链路灰度方案实现技术 4.3.1 标签路由 4.3.2 节点打标 4.3.3 流量染色 4.3.4 分布式链路…

MyBatis源码分析(二):项目结构

目录 1、前言 2、代码统计 3、整体架构 3.1、基础支持层 3.1.1、反射模块 3.1.2、类型模块 3.1.3、日志模块 3.1.4、IO模块 3.1.5、解析器模块 3.1.6、数据源模块 3.1.7、缓存模块 3.1.8、Binding 模块 3.1.9、注解模块 3.1.10、异常模块 3.2、核心处理层 3.2.…

Pytorch简介

1.1 Pytorch的历史 PyTorch是一个由Facebook的人工智能研究团队开发的开源深度学习框架。在2016年发布后&#xff0c;PyTorch很快就因其易用性、灵活性和强大的功能而在科研社区中广受欢迎。下面我们将详细介绍PyTorch的发展历程。 在2016年&#xff0c;Facebook的AI研究团队…

【C++】Ubuntu编译filezilla client

在新版Ubuntu 22.04.3 LTS上编译filezilla client成功&#xff0c;shell命令如下&#xff1a; sudo apt-get install libfilezilla-dev libwxbase3.0-dev gnutls-dev libdbus-1-dev sudo apt-get install libwxgtk3.0-gtk3-dev sudo apt-get install libgtk-3-dev sudo apt-ge…

【GO语言卵细胞级别教程】01.GO基础知识

01.GO基础知识 目录 01.GO基础知识1.GO语言的发展历程2.发展历程3.Windowns安装4.VSCode配置5.基础语法5.1 第一段代码5.2 GO执行的流程5.3 语法规则5.4 代码风格5.5 学习网址 1.GO语言的发展历程 Go语言是谷歌公司于2007年开始开发的一种编程语言&#xff0c;由Robert Griese…

Python从入门到精通之元类

系列 Python从入门到精通之安装与快速入门-CSDN博客 Python从入门到精通之基本数据类型和变量-CSDN博客 Python从入门到精通之集合&#xff08;List列表、Tuple元组、Dict字典、Set&#xff09;-CSDN博客 Python从入门到精通之条件语句、循环语句和函数-CSDN博客 Python从…

STM32疑难杂症

1.keil的奇怪问题 创建的数组分配内存到0x10000000地址的时候&#xff0c;数据总是莫名其妙的出现问题&#xff0c;取消勾选就正常了 stm32f407内部有一个CCM内存&#xff0c;这部分内存只能由内核控制&#xff0c;任何外设都不能够进行访问。这样问题就来了&#xff0c;如果使…

ES6 class详解

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…

基于SSM框架的宠物商城系统

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 功能模块&…