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 ...
随机推荐
- 使用 FHE 实现加密大语言模型
近来,大语言模型 (LLM) 已被证明是提高编程.内容生成.文本分析.网络搜索及远程学习等诸多领域生产力的可靠工具. 大语言模型对用户隐私的影响 尽管 LLM 很有吸引力,但如何保护好 输入给这些模型 ...
- 线上活动 | AI 头像变装秀
宝子们,你的头像多久没换了? 送你一个锦囊,让你拥有既独一无二,又千变万化的专属 AI 头像 Hugging Face 将在 7 月 5 日 发起:AI 头像变装秀 ️️️游戏规则️️️ 我们将分享 ...
- 【JAVA基础】时间处理
#时间处理 ##查询前台报表运单数据集 @ApiOperation(value = "查询前台报表运单数据集") @Permission(permissionPublic = tr ...
- CSS3 ------- object-fit属性
做项目经常会遇到图片列表展示,图片一般是用户从后台上传的,上传的图片尺寸千差万别.如果前端不控制图片大小,整个排版就会很乱,如果给定长宽,图片又会变形,用背景图片来处理有特别麻烦.这个问题一直苦恼了我 ...
- C++跨DLL内存所有权问题探幽(一)DLL提供的全局单例模式
最近在开发的时候,特别是遇到关于跨DLL申请对象.指针.内存等问题的时候遇到了这么一个问题. 问题 跨DLL能不能调用到DLL中提供的单例? 问题比较简单,就是我现在有一个进程A,有DLL B DLL ...
- Redis 常用五种数据类型编码
转载请注明出处: 目录 Redis 的五种数据结构 Redis 数据结构的内部编码 1.String 1.1 常用命令 1.2 内部编码 1.3 典型使用场景 2. Hash 2.1 常用命令及时间复 ...
- [转帖]TiDB的系统变量
TiDB 系统变量的行为与 MySQL 相似但有一些不同,变量的作用范围可以是全局范围有效 (Global Scope).实例级别有效 (Instance Scope) 或会话级别有效 (Sessio ...
- [转帖]TiUP Cluster 命令合集
https://docs.pingcap.com/zh/tidb/stable/tiup-component-cluster TiUP Cluster 是 TiUP 提供的使用 Golang 编写的集 ...
- [转帖]为什么不推荐使用/etc/fstab
https://www.jianshu.com/p/af49a5d0553f 对于工作中使用服务器的公司来讲,每到节假日来临时,总免不了对服务器进行下电.而收假回来的早上,则会有一个早上的时间会花费在 ...
- [转帖]谈谈对K8S CNI、CRI和CSI插件的理解
K8S的设计初衷就是支持可插拔架构,解决PaaS平台不好用.不能用.需要定制化等问题,K8S集成了插件.附加组件.服务和接口来扩展平台的核心功能.附加组件被定义为与环境的其他部分无缝集成的组件,提供类 ...