Pytest 源码解读 [1] - [pluggy] 核心设计理念浅读
背景:
Pytest 是一个功能强大的 Python 测试框架,它使用了一个名为 "pluggy" 的插件系统来扩展其功能。在 Pytest 的源码中,pluggy 模块负责实现插件管理和扩展机制。
核心类介绍:
PluginManager 类:PluginManager 是 pluggy 模块提供的一个类,用于管理插件的加载、注册和调用。它负责协调插件之间的交互,并控制钩子函数的执行顺序。
HookspecMarker 类:HookspecMarker 是 pluggy 模块提供的一个装饰器类,用于定义钩子函数规范。通过使用 HookspecMarker 装饰器,我们可以标识出一个函数作为钩子函数规范,以便在后续的插件中进行实现。
HookimplMarker 类:HookimplMarker 是 pluggy 模块提供的一个装饰器类,用于定义钩子函数的具体实现。通过使用 HookimplMarker 装饰器,我们可以将一个函数标识为钩子函数的具体实现,并将其注册到插件管理器中。
核心逻辑代码:
pm = PluginManager("pluggy_demo_1")
pm.add_hookspecs(HookSpec)
pm.register(HookImpl1())
pm.register(HookImpl2())
print(pm.hook.calculate(a=1, b=2))
首先,我们创建一个插件管理器 pm,并指定项目名称为 "pluggy_demo_1"。然后,我们使用 add_hookspecs() 方法将钩子函数规范 HookSpec 添加到插件管理器中。这样,插件管理器就知道了我们定义的钩子函数规范。
接下来,我们注册两个插件 HookImpl1() 和 HookImpl2() 到插件管理器中,通过调用 register() 方法。这样,插件管理器就知道了需要执行这两个插件的钩子函数。
最后,我们通过 pm.hook.calculate() 调用了钩子函数 calculate。pm.hook 是插件管理器提供的一个特殊属性,它允许我们访问所有已注册的钩子函数。通过调用 pm.hook.calculate(),插件管理器会触发所有已注册的 calculate 钩子函数,并将参数 a=1 和 b=2 传递给它们。
在插件中,我们可以根据具体需求实现 calculate 钩子函数的逻辑。可以有多个插件实现了该钩子函数,每个插件的实现可以根据自己的逻辑进行计算,并返回计算结果。
总结起来,这段代码中的 pm.hook.calculate 调用了已注册的 calculate 钩子函数,并触发了相应的插件逻辑。pm.hook 是插件管理器提供的特殊属性,用于访问已注册的钩子函数。通过调用该属性上的钩子函数,可以实现插件的扩展和自定义行为。
常用的 Pytest 钩子函数:
pytest_configure(config): 在 Pytest 运行之前,用于配置和初始化测试运行环境。pytest_collection_modifyitems(config, items): 在测试收集过程中修改测试项(test items)的钩子函数。pytest_runtest_protocol(item, nextitem): 在执行单个测试项之前和之后,以及在测试项之间进行干预的钩子函数。pytest_pyfunc_call(pyfuncitem): 在执行测试函数之前和之后进行干预的钩子函数。pytest_terminal_summary(terminalreporter): 在测试运行完成后,用于生成测试结果摘要的钩子函数。
自定义钩子函数步骤
步骤1:定义钩子函数接口(Hook specification)
- 创建一个 Python 模块,例如
myhooks.py。 - 在该模块中,使用
@pytest.hookspec装饰器来标记你的钩子函数接口。例如:
# myhooks.py
import pytest @pytest.hookspec
def my_custom_hook(arg1, arg2):
"""Documentation for the custom hook."""
pass
在这个例子中,my_custom_hook 是你的自定义钩子函数接口。你可以根据需要定义参数和返回值,以及提供相应的文档说明。
步骤2:实现钩子函数(Hook implementation)
- 创建另一个 Python 模块,例如
myplugin.py。 - 在该模块中,使用
@pytest.hookimpl装饰器来标记你的钩子函数实现。例如:
# myplugin.py
import pytest @pytest.hookimpl
def my_custom_hook(arg1, arg2):
"""Implementation of the custom hook."""
# 执行自定义的逻辑
print(f"Running custom hook with arguments: {arg1}, {arg2}")
return 42
在这个例子中,my_custom_hook 是你的自定义钩子函数实现。你可以在函数体内编写你的自定义逻辑,并返回相应的结果。
步骤3:注册自定义插件
- 创建一个用于注册插件的 Python 模块,例如
conftest.py。这个文件通常放置在测试目录的根目录或者tests目录下。 - 在
conftest.py中,使用pytest_configure钩子函数来注册你的插件。例如:
# conftest.py
def pytest_configure(config):
config.pluginmanager.register(myplugin)
在这个例子中,myplugin 是你在 myplugin.py 中定义的插件。通过调用 register 方法,你可以将插件注册到 Pytest 的插件管理器中。
步骤4:使用自定义钩子函数
- 在测试代码中,你可以通过使用
pytestconfig对象来访问自定义的钩子函数。 - 调用自定义钩子函数,并传入相应的参数。例如:
# test_myhooks.py
def test_with_custom_hook(pytestconfig):
hook_result = pytestconfig.hook.my_custom_hook(arg1=1, arg2=2)
# 处理钩子函数返回的结果
assert hook_result == 42
在这个例子中,我们通过 pytestconfig.hook 访问了自定义的钩子函数,并传入了参数 arg1 和 arg2。你可以根据你的钩子函数逻辑来处理返回的结果。
需要注意的是,为了让 Pytest 能够识别和加载自定义的钩子函数,确保将 myhooks.py、myplugin.py 和 conftest.py 放置在测试的搜索路径下,例如项目根目录或者 tests 目录下。
Pytest 源码解读 [1] - [pluggy] 核心设计理念浅读的更多相关文章
- SDWebImage源码解读之SDWebImageDownloaderOperation
第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...
- SDWebImage源码解读_之SDWebImageDecoder
第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...
- AFNetworking 3.0 源码解读 总结(干货)(上)
养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...
- AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking
AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...
- AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking
我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3个UIKit中的分类.UIAct ...
- AFNetworking 3.0 源码解读(八)之 AFImageDownloader
AFImageDownloader 这个类对写DownloadManager有很大的借鉴意义.在平时的开发中,当我们使用UIImageView加载一个网络上的图片时,其原理就是把图片下载下来,然后再赋 ...
- AFNetworking 3.0 源码解读(七)之 AFAutoPurgingImageCache
这篇我们就要介绍AFAutoPurgingImageCache这个类了.这个类给了我们临时管理图片内存的能力. 前言 假如说我们要写一个通用的网络框架,除了必备的请求数据的方法外,必须提供一个下载器来 ...
- AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager
做ios开发,AFNetworking 这个网络框架肯定都非常熟悉,也许我们平时只使用了它的部分功能,而且我们对它的实现原理并不是很清楚,就好像总是有一团迷雾在眼前一样. 接下来我们就非常详细的来读一 ...
- AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization
这篇就讲到了跟请求相关的类了 关于AFNetworking 3.0 源码解读 的文章篇幅都会很长,因为不仅仅要把代码进行详细的的解释,还会大概讲解和代码相关的知识点. 上半篇: URI编码的知识 关于 ...
- AFNetworking 3.0 源码解读(五)之 AFURLSessionManager
本篇是AFNetworking 3.0 源码解读的第五篇了. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager AFNetworking 3 ...
随机推荐
- Cmder - 想让你的windows下 cmd 和 SecureCRT 操作 Linux 一样帅吗 附字符集编码 chcp 936、chcp 65001
想让你的windows下 cmd 和 SecureCRT 操作 Linux 一样帅的命令行显示吗. 下载 cmder 绿色版,然后用我的配置文件,替换原来的文件启动就可以了 配置文件下载:cmder ...
- Kubernetes(K8S) 安装Nacos,报 No DataSource set
原因,数据库为 MySQL 5.7 需要在yaml加上参数 mysql.db.param: "characterEncoding=utf8&connectTimeout=1000&a ...
- 机器学习周刊第五期:一个离谱的数据可视化Python库、可交互式动画学概率统计、机器学习最全文档、快速部署机器学习应用的开源项目、Redis 之父的最新文章
date: 2024/01/08 这个网站用可视化的方式讲解概率和统计基础知识,很多内容还是可交互的,非常生动形象. 大家好,欢迎收看第五期机器学习周刊 本期介绍7个内容,涉及Python.概率统计. ...
- 【django-vue】登录注册模态框分析 登录注册前端页面 腾讯短信功能二次封装 短信验证码接口 短信登录接口 短信注册接口
目录 昨日回顾 csrf跨站请求伪造 接口幂等性 异常捕获 今日内容 1 登录注册模态框分析 Login.vue Header.vue 2 登录注册前端页面复制 2.0 Header.vue 2.1 ...
- # 2027 ( 统计元音 ) :hash应用
Problem Description 统计每个元音字母在字符串中出现的次数. Input 输入数据首先包括一个整数n,表示测试实例的个数,然后是n行长度不超过100的字符串. Output 对于每个 ...
- 师爷,翻译翻译什么叫AOP
张麻子:汤师爷,翻译翻译,什么叫AOP? 汤师爷:这还用翻译. 张麻子:我让你翻译给我听,什么叫AOP? 汤师爷:不用翻译,切面编程就是AOP啊. 黄四郎:难道你听不懂什么叫AOP? 张麻子:我就想让 ...
- kafka集群三、增加密码验证
系列导航 一.kafka搭建-单机版 二.kafka搭建-集群搭建 三.kafka集群增加密码验证 四.kafka集群权限增加ACL 五.kafka集群__consumer_offsets副本数修改 ...
- Mygin实现上下文
本篇是Mygin的第三篇 目的 将路由独立出来,方便后续扩展修改 上下文Context,对http.ResponseWriter和http.Request进行封装,实现对JSON.HTML等的支持 路 ...
- 【Mysql系列】(一)MySQL语句执行流程
首发博客地址 首发博客地址 系列文章地址 参考文章 MySQL 逻辑架构 连接器 连接命令一般是这么写的 mysql -h$ip -P$port -u$user -p 那么 什么是连接器? MySQL ...
- [转帖]【SOP】最佳实践之 TiDB 业务写变慢分析
https://zhuanlan.zhihu.com/p/647831844 前言 在日常业务使用或运维管理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题.这类问 ...