csdn最新最全pytest系列——pluggy插件源码解读(一)HookspecMarker类和HookimplMarker类分析

简介

pluggy是一个非常优秀的插件系统,它是理解pytest的核心,只有理解了pluggy的原理,才能更好的理解和使用pytest,否则见到了pytest的很多应用都会感觉很难理解

pluggy插件总共的代码量不足一千行,而实现的功能却是如此的强大和好用,这不由得让我们对pytest的源码实现充满了好奇,接下来一段时间就详细的由浅入深的来解读pluggy源码,这个过程中,同样会继续总结一些基础的或者高级的python的知识点。

当然随着对pluggy源码的深入,也会发现很多在网上书上博客上看不到的pluggy的高级应用,同样本系列都会使用实例演示和分析。

pluggy的简单应用

import pluggy# HookspecMarker 和 HookimplMarker 实质上是一个装饰器带参数的装饰器类,作用是给函数增加额外的属性设置
hookspec = pluggy.HookspecMarker("myproject")
hookimpl = pluggy.HookimplMarker("myproject")# 定义自己的Spec,这里可以理解为定义接口类
class MySpec:# hookspec 是一个装饰类中的方法的装饰器,为此方法增额外的属性设置,这里myhook可以理解为定义了一个接口@hookspecdef myhook(self, arg1, arg2):pass# 定义了一个插件
class Plugin_1:# 插件中实现了上面定义的接口,同样这个实现接口的方法用 hookimpl装饰器装饰,功能是返回两个参数的和@hookimpldef myhook(self, arg1, arg2):print("inside Plugin_1.myhook()")return arg1 + arg2# 定义第二个插件
class Plugin_2:# 插件中实现了上面定义的接口,同样这个实现接口的方法用 hookimpl装饰器装饰,功能是返回两个参数的差@hookimpldef myhook(self, arg1, arg2):print("inside Plugin_2.myhook()")return arg1 - arg2# 实例化一个插件管理的对象,注意这里的名称要与文件开头定义装饰器的时候的名称一致
pm = pluggy.PluginManager("myproject")
# 将自定义的接口类加到钩子定义中去
pm.add_hookspecs(MySpec)
# 注册定义的两个插件
pm.register(Plugin_1())
pm.register(Plugin_2())
# 通过插件管理对象的钩子调用方法,这时候两个插件中的这个方法都会执行,而且遵循后注册先执行即LIFO的原则,两个插件的结果讲义列表的形式返回
results = pm.hook.myhook(arg1=1, arg2=2)
print(results)

执行结果如下:

inside Plugin_2.myhook()
inside Plugin_1.myhook()
[-1, 3]

pluggy的文件组织结构

pluggy模块总共就有如下6个文件,总共代码行数不到1k行,这6个文件中,caller、hooks.py和manager.py是pluggy的最核心的部分

pluggy|--------__init__.py|--------_result.py|--------_tracing.py|--------caller.py|--------hooks.py|--------manager.py

 自动化测试相关教程推荐:

2023最新自动化测试自学教程新手小白26天入门最详细教程,目前已有300多人通过学习这套教程入职大厂!!_哔哩哔哩_bilibili

2023最新合集Python自动化测试开发框架【全栈/实战/教程】合集精华,学完年薪40W+_哔哩哔哩_bilibili

测试开发相关教程推荐

2023全网最牛,字节测试开发大佬现场教学,从零开始教你成为年薪百万的测试开发工程师_哔哩哔哩_bilibili

postman/jmeter/fiddler测试工具类教程推荐

讲的最详细JMeter接口测试/接口自动化测试项目实战合集教程,学jmeter接口测试一套教程就够了!!_哔哩哔哩_bilibili

2023自学fiddler抓包,请一定要看完【如何1天学会fiddler抓包】的全网最详细视频教程!!_哔哩哔哩_bilibili

2023全网封神,B站讲的最详细的Postman接口测试实战教学,小白都能学会_哔哩哔哩_bilibili

HookspecMarker类和HookimplMarker类分析

从上面的使用举例看,我们首先是看到了实例化了这两个类的实例,所以,我们就先从这两个类开始分析
下面看下HookspecMarker类的源码(在hooks.py文件中)

阅读源码有一个好处就是能发现一些比较高级的语法和比较好的用法,如果觉得读源码有难度,至少说明一点,我们对python的基础语法或者高级语法掌握的还不是很到位。比如下面
HookspecMarker类的定义,这里面涉及到python的两个相对高级一定的语法,一个是类中call魔法函数的作用,一个就是装饰器类,如果说对这两个知识点不清楚的话,那看到这个类就会有点头大了

class HookspecMarker:""" Decorator helper class for marking functions as hook specifications.You can instantiate it with a project_name to get a decorator.Calling :py:meth:`.PluginManager.add_hookspecs` later will discover all marked functionsif the :py:class:`.PluginManager` uses the same project_name."""def __init__(self, project_name):self.project_name = project_namedef __call__(self, function=None, firstresult=False, historic=False, warn_on_impl=None):""" if passed a function, directly sets attributes on the functionwhich will make it discoverable to :py:meth:`.PluginManager.add_hookspecs`.If passed no function, returns a decorator which can be applied to a functionlater using the attributes supplied.If ``firstresult`` is ``True`` the 1:N hook call (N being the number of registeredhook implementation functions) will stop at I<=N when the I'th functionreturns a non-``None`` result.If ``historic`` is ``True`` calls to a hook will be memorized and replayedon later registered plugins."""def setattr_hookspec_opts(func):if historic and firstresult:raise ValueError("cannot have a historic firstresult hook")setattr(func,self.project_name + "_spec",dict(firstresult=firstresult,historic=historic,warn_on_impl=warn_on_impl,),)return funcif function is not None:return setattr_hookspec_opts(function)else:return setattr_hookspec_opts

其实它的本质就是一个装饰器类,如果只把这个类实例化,即不用语法糖加在一个具体的函数上时,即此时返回的是一个setattr_hookimpl_opts,它的参数是另外一个被装饰的函数func,作用就是给被装饰的函数func设置一个属性,属性名就是初始化的时候传入的名称加上”_spec”,属性值时一个字典,字典里面有三个字段,分别是firstresult,historic和warm_on_impl

如下是HookspecMarker类的两种使用方法

import pluggyhookspec = pluggy.HookspecMarker("myproject")@hookspec
def test1():pass@pluggy.HookspecMarker("myproject2")
def test2():passprint(test1.myproject_spec)
print(test2.myproject2_spec)

执行结果为:

{'firstresult': False, 'historic': False, 'warn_on_impl': None}
{'firstresult': False, 'historic': False, 'warn_on_impl': None}

所以HookspecMarker类的本质就是为了给被装饰的函数对象增加这么一个属性

同理HookimplMarker类的代码如下,也同样是一个装饰器,也是为了给函数增加一个属性,属性名称为HookimplMarker类初始化时给的project_name加上”_impl”,其值主要有5个参数,至于每个参数做什么用的,可以到后面分析manager文件的时候再回头看

class HookimplMarker:""" Decorator helper class for marking functions as hook implementations.You can instantiate with a ``project_name`` to get a decorator.Calling :py:meth:`.PluginManager.register` later will discover all marked functionsif the :py:class:`.PluginManager` uses the same project_name."""def __init__(self, project_name):self.project_name = project_namedef __call__(self,function=None,hookwrapper=False,optionalhook=False,tryfirst=False,trylast=False,specname=None,):""" if passed a function, directly sets attributes on the functionwhich will make it discoverable to :py:meth:`.PluginManager.register`.If passed no function, returns a decorator which can be applied to afunction later using the attributes supplied.If ``optionalhook`` is ``True`` a missing matching hook specification will not resultin an error (by default it is an error if no matching spec is found).If ``tryfirst`` is ``True`` this hook implementation will run as early as possiblein the chain of N hook implementations for a specification.If ``trylast`` is ``True`` this hook implementation will run as late as possiblein the chain of N hook implementations.If ``hookwrapper`` is ``True`` the hook implementations needs to execute exactlyone ``yield``.  The code before the ``yield`` is run early before any non-hookwrapperfunction is run.  The code after the ``yield`` is run after all non-hookwrapperfunction have run.  The ``yield`` receives a :py:class:`.callers._Result` objectrepresenting the exception or result outcome of the inner calls (including otherhookwrapper calls).If ``specname`` is provided, it will be used instead of the function name whenmatching this hook implementation to a hook specification during registration."""def setattr_hookimpl_opts(func):setattr(func,self.project_name + "_impl",dict(hookwrapper=hookwrapper,optionalhook=optionalhook,tryfirst=tryfirst,trylast=trylast,specname=specname,),)return funcif function is None:return setattr_hookimpl_optselse:return setattr_hookimpl_opts(function)

下面用简单的代码演示HookimplMarker装饰器类给函数设置属性的结果

import pluggyhookspec = pluggy.HookimplMarker("myproject")@hookspec
def test1():pass@pluggy.HookimplMarker("myproject2")
def test2():passprint(test1.myproject_impl)
print(test2.myproject2_impl)

执行结果为:

{'hookwrapper': False, 'optionalhook': False, 'tryfirst': False, 'trylast': False, 'specname': None}
{'hookwrapper': False, 'optionalhook': False, 'tryfirst': False, 'trylast': False, 'specname': None}

至此 HookspecMarker类和HookimplMarker类的代码就分析完了

 总结:

 光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

如果对你有帮助的话,点个赞收个藏,给作者一个鼓励。也方便你下次能够快速查找。

如有不懂还要咨询下方小卡片,博主也希望和志同道合的测试人员一起学习进步

在适当的年龄,选择适当的岗位,尽量去发挥好自己的优势。

我的自动化测试开发之路,一路走来都离不每个阶段的计划,因为自己喜欢规划和总结,

测试开发视频教程、学习笔记领取传送门!!

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

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

相关文章

IDEA 配置maven结合案例使用篇

1. 项目需求和结构分析 需求案例&#xff1a;搭建一个电商平台项目&#xff0c;该平台包括用户服务、订单服务、通用工具模块等。 项目架构&#xff1a; 用户服务&#xff1a;负责处理用户相关的逻辑&#xff0c;例如用户信息的管理、用户注册、登录等。 spring-context 6.0.…

5-2计算pi

#include<stdio.h> #include<math.h>int main(){int sign1;//数值的符号int count0;//累计计算循环的次数double pi0.0;double n1;//分母double term1.0;//当前项的数while(fabs(term)>1e-6){//fabs(trem)|term|pipiterm;nn2;sign-sign;termsign/n;count;}pipi*…

基于Vue3的低代码开发平台——JNPF

目录 一、什么是Vue.js &#xff1f; 二、Jnpf-Web-Vue3 的技术栈介绍 &#xff08;1&#xff09;Vue3.x &#xff08;2&#xff09;Vue-router4.x &#xff08;3&#xff09;Vite4.x &#xff08;4&#xff09;Ant-Design-Vue3.x &#xff08;5&#xff09;TypeScript &#x…

【Java】实现阻塞队列-生产者/消费者模型

上文中我们讲了Java库中自带的阻塞队列&#xff0c;并且讲了如何用阻塞队列来实现生产者消费者模型 【Java】用Java库中自带的阻塞队列以及用阻塞队列实现生产者-消费者模型 下面我们来讲如何用代码实现一个阻塞队列 1、实现一个阻塞队列 阻塞队列 普通队列 线程安全 阻…

机器学习实战第1天:鸢尾花分类任务

专栏介绍 欢迎订阅专栏——机器学习实战 机器学习实战_Nowl的博客-CSDN博客 纸上得来终觉浅 本专栏项目将着重于解决各类实际机器学习问题&#xff0c;带你上手各种场景的实际问题 数据集可以在我的资源中找到&#xff0c;也可以自行搜索 文中导入数据集的路径要改成自己的…

C++学习笔记——C++ deque和vector的区别

C中的std::deque&#xff08;双端队列&#xff09;和std::vector&#xff08;向量&#xff09;是两种不同的容器类型&#xff0c;它们有以下区别&#xff1a; 内部实现方式不同&#xff1a;std::deque使用了一种双端队列的数据结构&#xff0c;它由多个块&#xff08;chunks&am…

【操作系统】文件系统的实现

文章目录 文件系统的层次结构文件系统的实现目录实现线性列表哈希表 文件的实现连续分配链接分配索引分配 文件存储空间管理空闲表法与空闲链表法成组链接法位示图法 文件系统的层次结构 文件系统从上往下分为了五层&#xff0c;分别是用户调用接口、文件目录系统、存取控制模…

SWT/Jface(1): 表格的创建和渲染

前言 使用JFace创建表格还是比较方便的, 如果仅仅是创建空表格的话, 以下2步即可完成: 创建TableViewer对象, 指定样式, 比如是否支持多行选择, 有无边框, 是否支持滚动条等创建TableColumn对象: 包括列展示名称, 宽度和样式等, 最终绑定到table对象 实例 创建表格 //注意…

设计模式-学习总结

学习总结 本文仅供自我学习使用 我是一个小白设计模式一.创建型模式1.单例模式(1).饿汉式(2).懒汉式&#xff0c;双检锁(3).静态内部类(4).枚举 2.原型模式3.工厂模式(1).简单工厂模式 4.抽象工厂模式5.建造者模式 二.结构型模式6.适配器模式7.组合模式8.装饰器模式9.外观模式1…

【AI】行业消息精选和分析(11月22日)

今日动态 &#x1f453; Video-LLaVA&#xff1a;视觉语言模型革新&#xff1a; - 图像和视频信息转换为文字格式。 - 多模态理解能力&#xff0c;适用于自动问答系统等。 &#x1f4c8; 百度文心一言用户数达7000万&#xff1a; &#x1f50a; RealtimeTTS&#xff1a;实时文本…

SpringBoot : ch06 整合 web (一)

前言 SpringBoot作为一款优秀的框架&#xff0c;不仅提供了快速开发的能力&#xff0c;同时也提供了丰富的文档和示例&#xff0c;让开发者更加容易上手。在本博客中&#xff0c;我们将介绍如何使用SpringBoot来整合Web应用程序的相关技术&#xff0c;并通过实例代码来演示如何…

《微信小程序案例大全》大学生期末大作业可以直接使用!!

前言 在大学生活中&#xff0c;期末大作业是锻炼和展示自己所学知识的重要时刻。微信小程序作为一种快速、便捷的应用开发方式&#xff0c;成为了大学生开发实践的热门选择。本文将为大家推荐一系列可以直接使用的微信小程序案例&#xff0c;包括仿真社交、图书管理、学习工具…

接口自动化测试实战经验分享,测试用例也能自动生成

作为测试&#xff0c;你可能会对以下场景感到似曾相识&#xff1a;开发改好的 BUG 反复横跳&#xff1b;版本兼容逻辑多&#xff0c;修复一个 BUG 触发了更多 BUG&#xff1b;上线时系统监控毫无异常&#xff0c;过段时间用户投诉某个页面无数据&#xff1b;改动祖传代码时如履…

CentOS 7 使用pugixml 库

安装 pugixml Git下载地址&#xff1a;https://github.com/zeux/pugixml 步骤1&#xff1a;首先&#xff0c;你需要下载pugixml 的源代码。你可以从Github或者源代码官方网站下载。并上传至/usr/local/source_code/ 步骤2&#xff1a;下载完成后&#xff0c;需要将源代码解压…

利用QRCode.js生成动态二维码页面

文章目录 QRCode.js简介HTML结构JavaScript生成动态二维码拓展功能1. 联系信息二维码2. Wi-Fi网络信息二维码 总结 &#x1f389;利用QRCode.js生成动态二维码页面 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;该系列文章专栏…

微信小程序开发者工具] ? Enable IDE Service (y/N) ESC[27DESC[27C

在HBuilder运行微信小程序开发者工具报错 如何解决 打开微信小程序开发者工具打开设置--->安全设置--->服务器端口选择打开就可以啦

《C++ Primer》第9章 顺序容器(三)

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 9.5 额外的string操作&#xff08;P320&#xff09; 9.5.1 构造string的其他方法 const char *cp "hello, world!"; char arr[] { h,\0,i,\0 }; string s1(cp); // s1 "hello, world!…

C#中的var究竟是强类型还是弱类型?

前言 在C#中&#xff0c;var关键字是用来声明变量类型的&#xff0c;它是C# 3.0推出的新特征&#xff0c;它允许编译器根据初始化表达式推断变量类型&#xff0c;有点跟javascript类似&#xff0c;而javascript中的var是弱类型。它让C#变量声明更加简洁&#xff0c;但也导致了…

算法设计与分析复习--分支界限法

文章目录 上一篇分支界限法性质装载问题0-1背包问题单源最短路问题最大团问题下一篇 上一篇 算法设计与分析复习–回溯法&#xff08;二&#xff09; 分支界限法性质 分支界限法是按广度优先策略或最小耗费优先遍历问题的解空间树。 搜索解空间&#xff1a; 子集树排列树 …

APP自动化之Poco框架

今天给大家介绍一款自动化测试框架Poco&#xff0c;其脚本写法非常简洁、高效&#xff0c;其元素定位器效率更快&#xff0c;其本质基于python的第三方库&#xff0c;调试起来也会非常方便&#xff0c;能够很好的提升自动化测试效率&#xff0c;节省时间。 (一&#xff09;背景…