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.hqwc.cn/news/206805.html

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

相关文章

RTS 客户端-服务器网络

Stone Monarch 从一开始就支持多人游戏&#xff0c;但随着时间的推移&#xff0c;网络模型经历了多次迭代。我最初基于这篇著名的帝国时代文章实现了点对点锁步模型。 点对点锁定步骤有一些众所周知的问题。点对点方面使玩家很难相互连接&#xff0c;并增加了每个新玩家的网络…

vivado产生报告阅读分析15-时序报告11

Report Clock Domain Crossings “ Clock Domain Crossings (CDC) ” &#xff08; 时钟域交汇 &#xff09; 报告可对设计中的时钟域交汇执行结构分析。此信息可用于识别潜在不安全的 CDC &#xff0c; 此类 CDC 可能导致亚稳态或数据一致性问题。虽然 CDC 报告与“ Clock …

PostMan接口测试教程

1、下载和安装 Postman: 前往 Postman 官网 &#xff08;https://www.postman.com&#xff09;&#xff0c;下载适用于你的操作系统的 Postman 客户端。 执行下载后的安装程序&#xff0c;并按照安装向导的指引完成安装过程。 2、创建一个新的集合&#xff1a; 打开 Postma…

Python配置与测试利器:Hydra + pytest的完美结合

简介&#xff1a;Hydra 和 pytest 可以一起使用&#xff0c;基于 Hydra Pytest 的应用可以轻松地管理复杂配置&#xff0c;并编写参数化的单元测试&#xff0c;使得Python开发和测试将变得更为高效。 安装&#xff1a; pip install hydra-core pytest案例源码&#xff1a;my…

LabVIEW如何获取波形图上游标所在位置的数值

LabVIEW如何获取波形图上游标所在位置的数值 获取游标所在位置数值的一种方法是利用波形图的游标列表属性。 在VI的程序框图中&#xff0c;右键单击波形图并选择创建引用 &#xff0c;然后将创建的引用节点放在程序框图上。 在程序框图上放置一个属性节点&#xff0c;并将其…

马斯克震撼演讲:我想创立一个新世界

目录 1拼多多杀入大模型领域&#xff1a;年薪百万招聘人才 2马斯克震撼演讲&#xff1a;我想创立一个新世界 3文心4.0上线首交答卷&#xff1a;百度2023Q3成色如何 1拼多多杀入大模型领域&#xff1a;年薪百万招聘人才 快科技11月22日消息&#xff0c;据国内媒体报道&#x…

【c++】——类和对象(下) 万字解答疑惑

作者:chlorine 专栏:c专栏 目录 &#x1f6a9;再谈构造函数 &#x1f393;构造函数体赋值 &#x1f393;初始化列表 &#x1f6a9;explicit关键字 &#x1f6a9;static成员 &#x1f393;概念 面试题&#xff1a;计算创建多少个类对象 &#x1f393;特性 【问题】(非)…

低成本打造便携式无线网络攻防学习环境

1.摘要 一直以来, 无线网络安全问题与大众的个人隐私息息相关, 例如: 为了节省流量, 连接到一个看似安全的免费WiFi, 在使用过程中泄露自己的各类密码信息甚至银行卡账号密码信息。随着家用智能电器的普及, 家中的各类智能设备连入家里的无线网络, 却突然失灵, 甚至无法正常连…

shopee数据分析软件:了解市场趋势,分析竞争对手,优化运营策略

在当今数字化时代&#xff0c;数据已经成为了企业决策的重要依据。对于电商行业来说&#xff0c;数据更是至关重要。如果你想在电商领域中脱颖而出&#xff0c;那么你需要一款强大的数据分析工具来帮助你更好地了解市场、分析竞争对手、优化运营策略。而知虾数据软件就是这样一…

【考研数学】数学一“背诵”手册(一)| 高数部分(2)

文章目录 引言一、高数级数空间解析几何球坐标变换公式零碎公式 写在最后 引言 高数一篇文章还是写不太下&#xff0c;再分一些到这里来吧 一、高数 级数 阿贝尔定理&#xff1a;若级数 ∑ a n x n \sum a_nx^n ∑an​xn 当 x x 0 xx_0 xx0​ 时收敛&#xff0c;则适合不…

VulnHub DC-9

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

Flutter开发实践:用一套代码构建多端精美应用

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…