测试开发技术网站
博客
设计
设计
开发
Python
测试
unittest
运维
Linux基础应用
CI/CD
CI/CD
数据库
数据库
云计算
云计算
云原生
云原生
爬虫
爬虫
数据分析
数据分析
人工智能
人工智能
登录
注册
Pluggy源码解读----Pluggy模块的应用
收藏本文
作者:redrose2100 类别: 日期:2022-12-09 06:05:16 阅读:1210 次 消耗积分:0 分
[TOC] ![](https://redrose2100.oss-cn-hangzhou.aliyuncs.com/img/7cd47362-951c-11ee-986a-0242ac110004.png) pluggy 模块简单理解就是一个插件系统,pytest自动化测试框架的核心就是pluggy,简单点理解pytest就是基于pluggy将一系列的插件组装在一起的一个测试框架,因此这里首先介绍pluggy模块的使用方法。 首先安装pluggy模块,执行如下命令。 ```bash pip install pluggy ``` 然后编写如下一段实例代码,这里面主要有三个类,其中MySpec类可以简单理解为接口类,而Plugin_1和Plugin_2可以理解为实现类,也可以理解为插件,即对同一个接口可以有多个实现,在主函数中pm可以理解为一个插件管理器,pm.add_hookspecs则是为插件系统增加接口,pm.register则是插件注册的过程,当插件注册后,pm.hook.myhook则会执行myhook函数,当有多个插件注册而且有多个插件中都实现了接口函数后,则每个插件的接口函数都会执行,而且按照先进后出的顺序即后注册先执行的顺序将所有注册了的插件总的该方法执行一遍。 ```python import pluggy hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") class MySpec: @hookspec def myhook(self, arg1, arg2): pass class Plugin_1: @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_1.myhook()") return arg1 + arg2 class Plugin_2: @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_2.myhook()") return arg1 - arg2 if __name__=="__main__": pm = pluggy.PluginManager("myproject") pm.add_hookspecs(MySpec) pm.register(Plugin_1()) pm.register(Plugin_2()) results = pm.hook.myhook(arg1=1, arg2=2) print(results) ``` 执行结果如下,可以看到这里先执行了Plugin_2中的myhook方法,然后执行Plugin_1中的myhook方法,,并且按照此顺序将每个插件中的方法返回值放在列表中返回。 ```bash (demo-HCIhX0Hq) E:\demo>python demo.py inside Plugin_2.myhook() inside Plugin_1.myhook() [-1, 3] (demo-HCIhX0Hq) E:\demo> ``` 下面再看一个更为复杂一点的实例,如下代码,这里可以理解为MySpec类定义了四个接口函数,分别是myhook1、myhook2、myhook3、myhook4,然后定义了两个插件类,插件Pluggin_1实现了myhook1、myhook2、myhook3,而插件Pluggin_2实现myhook2、myhook3、myhook4。 ```python import pluggy hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") class MySpec: @hookspec def myhook1(self, arg1, arg2): pass @hookspec def myhook2(self, arg1, arg2): pass @hookspec def myhook3(self, arg1, arg2): pass @hookspec def myhook4(self, arg1, arg2): pass class Plugin_1: @hookimpl def myhook1(self, arg1, arg2): print("inside Plugin_1.myhook1()") return arg1 + arg2 @hookimpl def myhook2(self, arg1, arg2): print("inside Plugin_1.myhook2()") return arg1 + arg2 +1 @hookimpl def myhook3(self, arg1, arg2): print("inside Plugin_1.myhook4()") return arg1 + arg2 + 2 class Plugin_2: @hookimpl def myhook2(self, arg1, arg2): print("inside Plugin_2.myhook2()") return arg1 - arg2 @hookimpl def myhook3(self, arg1, arg2): print("inside Plugin_2.myhook3()") return arg1 - arg2 - 1 @hookimpl def myhook4(self, arg1, arg2): print("inside Plugin_2.myhook4()") return arg1 - arg2 - 2 if __name__=="__main__": pm = pluggy.PluginManager("myproject") pm.add_hookspecs(MySpec) pm.register(Plugin_1()) pm.register(Plugin_2()) results = pm.hook.myhook1(arg1=1, arg2=2) print(results) results = pm.hook.myhook2(arg1=1, arg2=2) print(results) results = pm.hook.myhook3(arg1=1, arg2=2) print(results) results = pm.hook.myhook4(arg1=1, arg2=2) print(results) ``` 执行结果如下,因为myhook1只有一个插件实现,因此返回值只有一个,myhook2和myhook3分别有两个插件实现,因此返回值有两个,并且按照先进后出的顺序存入列表,同样myhook4也只有一个插件定义,因此也只有一个返回值。 ```bash (demo-HCIhX0Hq) E:\demo>python demo.py inside Plugin_1.myhook1() [3] inside Plugin_2.myhook2() inside Plugin_1.myhook2() [-1, 4] inside Plugin_2.myhook3() inside Plugin_1.myhook4() [-2, 5] inside Plugin_2.myhook4() [-3] (demo-HCIhX0Hq) E:\demo> ``` 在定义接口的时候还可以通过firstresult=True指定只要有一个结果正确返回了就结束。,如下代码,在定义myhook的时候通过装饰器传参指定了firstresult=True,这样在执行的时候,注册了Pluggin_1和Pluggin_2两个插件,当然按照后进先出的顺序,首先执行Pluggin_2插件中的,此时能够正确返回,那么就结束了,不会再去执行Plugging_1中的myhook了。当然这是通过代码分析出来的,下面通过执行结果验证。 ```python import pluggy hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") class MySpec: @hookspec(firstresult=True) def myhook(self, arg1, arg2): pass class Plugin_1: @hookimpl def myhook(self, arg1, arg2): print("in Plugin_1.myhook()") return arg1 + arg2 class Plugin_2: @hookimpl def myhook(self, arg1, arg2): print("in Plugin_2.myhook()") return arg1 - arg2 pm = pluggy.PluginManager("myproject") pm.add_hookspecs(MySpec) pm.register(Plugin_1()) pm.register(Plugin_2()) results = pm.hook.myhook(arg1=1, arg2=2) print(results) ``` 执行结果如下,可以看到这里只执行了Plugin_2类中的myhook方法,Plugin_1类中的 ```bash (demo-HCIhX0Hq) E:\demo>python demo.py in Plugin_2.myhook() -1 ``` 此外还可以通过tryfirst或trylast指定当前类最先执行或者最后执行。比如如下代码,定会了三个插件类,在第二个类中使用tryfirst指定当前最先执行。 ```python import pluggy hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") class MySpec: @hookspec def myhook(self, arg1, arg2): pass class Plugin_1: @hookimpl def myhook(self, arg1, arg2): print("in Plugin_1.myhook()") return arg1 + arg2 class Plugin_2: @hookimpl(tryfirst=True) def myhook(self, arg1, arg2): print("in Plugin_2.myhook()") return arg1 - arg2 class Plugin_3: @hookimpl def myhook(self, arg1, arg2): print("in Plugin_3.myhook()") return arg1 - arg2+10 pm = pluggy.PluginManager("myproject") pm.add_hookspecs(MySpec) pm.register(Plugin_1()) pm.register(Plugin_2()) pm.register(Plugin_3()) results = pm.hook.myhook(arg1=1, arg2=2) print(results) ``` 执行结果如下,可以看出此时首先执行了Plugin_2类。 ```bash (demo-HCIhX0Hq) E:\demo>python demo.py in Plugin_2.myhook() in Plugin_3.myhook() in Plugin_1.myhook() [-1, 9, 3] (demo-HCIhX0Hq) E:\demo> ``` 同样可以通过trylast指定当前类最后执行,比如这里把Plugin_2中的tryfirst修改为trylast,再次执行结果如下: ```bash (demo-HCIhX0Hq) E:\demo>python demo.py in Plugin_3.myhook() in Plugin_1.myhook() in Plugin_2.myhook() [9, 3, -1] (demo-HCIhX0Hq) E:\demo> ``` 当传入hookwrapper=True时,需要在这个plugin中实现一个yield,plugin先执行yield之前的代码,然后去执行其他的pluggin,然后再回来执行yield之后的代码,同时通过yield可以获取到其他插件执行的结果。如下所示,在Plugin_2中使用了yield,在yield执行完成后可以获取到所有插件的执行结果,比如这里output,同时当所有yield周的代码执行完成之后,仍然是可以获取到所有插件的返回值列表的。 ```python import pluggy hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") class MySpec: @hookspec def myhook(self, arg1, arg2): pass class Plugin_1: @hookimpl() def myhook(self, arg1, arg2): print("in Plugin_1.myhook()") return arg1 + arg2 class Plugin_2: @hookimpl(hookwrapper=True) def myhook(self, arg1, arg2): print("in Plugin_2.myhook() before yield...") output=yield result=output.get_result() print("in Plugin_2.myhook() after yield...") print(result) class Plugin_3: @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_3.myhook()") return arg1 - arg2+10 pm = pluggy.PluginManager("myproject") pm.add_hookspecs(MySpec) pm.register(Plugin_1()) pm.register(Plugin_2()) pm.register(Plugin_3()) results = pm.hook.myhook(arg1=1, arg2=2) print("after all run ...") print(results) ``` 执行结果如下,可以看到在Plugin_2中yield语句之后以及在所有代码执行完成后,都可以获取所有插件的返回值。 ```bash (demo-HCIhX0Hq) E:\demo>python demo.py in Plugin_2.myhook() before yield... inside Plugin_3.myhook() in Plugin_1.myhook() in Plugin_2.myhook() after yield... [9, 3] after all run ... [9, 3] (demo-HCIhX0Hq) E:\demo> ```
始终坚持开源开放共享精神,同时感谢您的充电鼓励和支持!
版权所有,转载本站文章请注明出处:redrose2100, http://blog.redrose2100.com/article/488
上一篇:
Pytest----pytest-tldr 插件简化脚本执行日志输出
下一篇:
Pluggy源码解读----pluggy源码解读基础准备
搜索
个人成就
出版书籍
《Pytest企业级应用实战》
测试开发技术全栈公众号
测试开发技术全栈公众号
DevOps技术交流微信群
加微信邀请进群
常用网站链接
开源软件洞察
云原生技术栈全景图
Python语言官方文档
Golang官方文档
Docker官方文档
Jenkins中文用户手册
Scrapy官方文档
VUE官方文档
Harbor官方文档
openQA官方文档
云原生开源社区
开源中国
Kubernetes中文文档
Markdown语法官方教程
Kubernetes中文社区
Kubersphere官方文档
BootStrap中文网站
JavaScript中文网
NumPy官方文档
Pandas官方文档
GitLink确实开源网站
数据库排名网站
编程语言排名网站
SEO综合查询网站
数学加减法练习自动生成网站
Kickstart Generator
文章分类
最新文章
最多阅读
特别推荐
×
Close
登录
注册
找回密码
登录邮箱:
登录密码:
图片验证码:
注册邮箱:
注册密码:
邮箱验证码:
发送邮件
注册邮箱:
新的密码:
邮箱验证码:
发送邮件