首页 > 编程语言 >Pytest 源码解读 [1] - [pluggy] 插件框架介绍

Pytest 源码解读 [1] - [pluggy] 插件框架介绍

时间:2024-01-26 20:13:02浏览次数:28  
标签:插件 calculate plugin class hook Pytest 源码 pluggy pm

Pluggy
  • (https://github.com/pytest-dev/pluggy)
  • Pytest 的核心实际的基于 Pluggy 这个 plugin framework 的,实际上 pytest 本身就是由一个一个插件组成的
  • 本来 pluggy 的代码是在 pytest 的 repo 里,后来迁移了出来,作为一个独立的项目。Pluggy 作为一个独立的plugin framework 来看也是很优雅的存在

 

一个简单的Demo

Pluggy 已经从之前的 Pytest源码中独立出了一个单独的 Repo , 对于 Pytest自身也是把它作为一个外部的依赖来使用,我们这里就用一个独立的 Python 项目来 Demo,先看代码

from pluggy import HookspecMarker, HookimplMarker, PluginManager

spec = HookspecMarker("pluggy_demo_1")
impl = HookimplMarker("pluggy_demo_1")


class HookSpec:
    @spec(historic=True)
    def calculate(self, a, b):
        pass

class HookImpl1:
    @impl
    def calculate(self, a, b):
        return a + b

pm = PluginManager("pluggy_demo_1")
pm.add_hookspecs(HookSpec)
pm.register(HookImpl1())
pm.hook.calculate(a=1, b=2)

 


Output

[3]

 


解释

  • Pluggy的核心就是三个类 HookspecMarkerHookimplMarker,PluginManager,核心的插件逻辑就是定义了一组 hook 的方法,然后 plugin 是hook 方法的具体实现
  • 整个 Project 需要用一个全局唯一的 Project Name ,这里是 pluggy_demo_1
  • HookSpec是一个申明 hook method 的 class ,每一个 hook method 需要用spec的装饰器来装饰
  • HookImpl1 是一个 plugin 的实现,需要完整实现对应的hook方法,并且通过impl装饰器来装饰
  • 核心代码的调用逻辑就是先创建一个PluginManager对象,注册 Spec 和对应的 plugin 对象,然后通过 PluginManager自带的 hook 变量来调用对应的hook方法,传入相关的参数即可。切记在调用 hook 的时候参数必须是通过关键字的方式来传递

hook 和 plugin 的关系

hook 和 plugin 的对应关系是 1:N,如果说注册了多个实现了同一个 hook 的 plugin ,会返回多个结果,我们来看这个例子

from pluggy import HookspecMarker, HookimplMarker, PluginManager

spec = HookspecMarker("pluggy_demo_1")
impl = HookimplMarker("pluggy_demo_1")


class HookSpec:
    @spec
    def calculate(self, a, b):
        pass


class HookImpl1:
    @impl
    def calculate(self, a, b):
        return a + b


class HookImpl2:
    @impl
    def calculate(self, a, b):
        return a * b


pm = PluginManager("pluggy_demo_1")
pm.add_hookspecs(HookSpec)
pm.register(HookImpl1())
pm.register(HookImpl2())
print(pm.hook.calculate(a=1, b=2))

 


Output

[2,3]

 


解释

  • 在这里我们注册了两个 plugin , HookImpl1和 HookImpl2,分别对应了加法和乘法的两个不同逻辑

  • 一次 hook 的调用返回了2个plugin 执行的结果,注意一下这里是先执行后注册的 HookImpl2,再执行先注册的HookImpl1, 下次具体分析 pluggy 实现的时候会解释

plugin 调用顺序

HookimplMarker 装饰器参数

HookimplMarker 装饰器支持一些特定的参数

  • tryfirst - 顾名思义就是这个 plugin 在 1:N 的执行链路中先执行
  • trylast - 顾名思义后执行
  • hookwrapper - 基于 yield 实现的一个wrapper,先执行 wrapper plugin 的一部分逻辑,然后执行其他 plugin,最后执行剩余的 wrapper plugin 逻辑

tryfirst

我们修改一下刚才那个demo,把HookImpl1加上tryfirst参数, 执行的顺序就变了

class HookImpl1:
    @impl(tryfirst=True)
    def calculate(self, a, b):
        return a + b   

 


Output

[3,2]

 

HookspecMarker 装饰器参数

hookwrapper

这里我们实现一个特殊 plugin ImplWrapper,先看代码

from pluggy import HookspecMarker, HookimplMarker, PluginManager

spec = HookspecMarker("plugin_demo_2")
impl = HookimplMarker("plugin_demo_2")
pm = PluginManager("plugin_demo_2")


class Spec:
    @spec
    def calculate(self, a, b):
        pass


class Impl1:
    @impl
    def calculate(self, a, b):
        return a + b


class Impl2:
    @impl(tryfirst=True)
    def calculate(self, a, b):
        return a + b + 2


class ImplWrapper:
    @impl(hookwrapper=True)
    def calculate(self, a, b):
        print("before logic")
        outcome = yield
        print("Get Result %s" % outcome.result)
        return a * b * 10


pm.add_hookspecs(Spec)
pm.register(Impl1())
pm.register(Impl2())
pm.register(ImplWrapper())
print(pm.hook.calculate(a=1, b=2))

 

Output

before logic
Get Result [5, 3]
[5, 3]

 


解释

  • ImplWrapper 是一个类似 coroutine的 生成器,它有两段逻辑,用outcome = yield来分割
  • outcome 通过 yield来获取,它是_Result对象,包含了非wrapper 的 plugin 的执行结果,这里就是 Impl1 和 Impl2,从实际的output来看,Get Result [5,3]就是获取了返回值
  • wrapper plugin 的返回值是会被 ignore 的,具体的原因下次分析源码的时候会给解释

HookspecMarker 装饰器参数

HookspckMarker装饰器也支持一些参数,主要是

  • firstresult - 获取第一个plugin 执行结果后就中断后续执行
  • historic - 表示这个 hook 是需要保存call history 的,当有新的 plugin 注册的时候,需要回放历史

firstresult

调整一下 HookSpec,添加 firstresult参数,我们看一下执行结果

class Spec:
    @spec(firstresult)
    def calculate(self, a, b):
        pass
        
class HookImpl1:
    @impl(tryfirst=True)
    def calculate(self, a, b):
        return a + b  

 


Output

[2]

 

原文链接:https://markshao.github.io/2019/10/01/pluggy-guideline/

标签:插件,calculate,plugin,class,hook,Pytest,源码,pluggy,pm
From: https://www.cnblogs.com/superbaby11/p/17990592

相关文章

  • 通达信金拐杖选股指标公式源码大智慧通用
    VAR2:=CLOSE*VOL;VAR3:=EMA((EMA(VAR2,3)/EMA(VOL,3)+EMA(VAR2,6)/EMA(VOL,6)   +EMA(VAR2,12)/EMA(VOL,12)+EMA(VAR2,24)/EMA(VOL,24))/4,13);白线:=1.06*VAR3;XG1:=C>白线;D:=72;VAR1:=(HHV(HIGH,8)-CLOSE)/(HHV(HIGH,20)-LLV(LOW,20))*100;VARK2:=(CLOSE-L......
  • 通达信SAR操盘手主图指标公式源码
    X1:=(C+L+H)/3;X2:=Ema(X1,6);X3:=EMA(X2,5);{DRAWICON(crOSS(X2,X3),L-1,7);DRAWICON(CROSS(X3,X2),H+1,8);}stICKLINE(X2>=X3,LOW,HIGH,0,1),COLORRED;STICKLINE(X2>=X3,CLOSE,OPEN,3.2,2),COLORRED;STICKLINE(X2<x3,low,high,0,1),colorgreen;<b......
  • 通达信强势回调主图指标公式源码
    stICKLINE(C/REF(C,1)>1.099,C,O,2.3,0),COLORYELLOW;V1:=IF(NAMELIKE('S')ORNAMELIKE('*'),5,10);C3:=REF(C,1);BBB:=IF((C-C3)*100/C3>=(V1-0.01*100/C3)ANDC=H,1,0);ZT:=BArslAST(BBB)+1;STICKLINE(ZTANDZT<15,REF(C,ZT-1),REF......
  • 通达信极品高抛低吸指标公式源码副图
    S1:=(HHV(HIGH,9)-CLOSE)/(HHV(HIGH,9)-LLV(LOW,9))*100-70;S2:=SMA(S1,9,1)+100;S3:=(CLOSE-LLV(LOW,9))/(HHV(HIGH,9)-LLV(LOW,9))*100;S4:=Sma(S3,3,1);S5:=SMA(S4,3,1)+100;S6:=S5-S2;主力线:=IF(S6>45,S6-45,0);VAR2:=(CLOSE-LLV(LOW,24))/(HHV(HIGH,24)-LLV(LOW,......
  • 通达信上下电梯指标公式源码
    快:COUNT(CLOSE>REF(CLOSE,2),4)/4*100,COLOR00FF00;慢:COUNT(CLOSE>REF(CLOSE,2),6)/6*100,COLORFFFFFF;备钱:IF(快=0AND慢>20,20,0),COLORFF00FF;低买:IF(快=0ANDBETWEEN(慢,1,20),50,0),COLORRED;关注:IF(快=0AND慢=0,10,0),COLORFF8800;JC:=(crOSS(快,1)AND慢<=4......
  • 基于Java和Vue开发的企业Ehr数智化人力管理系统源码+配套文档(提升人力资源管理效率的
    写在前面:随着企业规模的不断扩大和人力资源管理的日益复杂,传统的人力资源管理方式已经无法满足现代企业的需求。为了提高管理效率、优化资源配置、降低人力成本,越来越多的企业开始引入eHR人力资源管理系统。本文将重点介绍eHR系统在招聘管理、人事管理、考勤管理、绩效管理、社保......
  • 通达信【红影】今买明卖T+1超短线神器 实盘图例 主图幅图选股公式 源码文件分享
    通达信红影主图幅图选股公式今买明卖T+1超短线神器实盘图例源码文件分享某地金钻指标,原价2000哦,原公式完全加密,股海网和谐源码文件分享所谓红影,就是出现长上影线后收的红色K线,长上影线,代表有很强的资金能量拉升,收红色K线代表多大占据优势,次日大概率有冲高动能,原理非常简单,很......
  • 通达信猛牛异动线主图指标公式源码
    上:Ema(C,3),COLORYELLOW;天:EMA(C,5),COLOR00FF00;入:EMA(天,5),COLORWHITE,;VARF1:=COUNT(crOSS(上,入),2)=1;VARF2:=COUNT(CROSS(天,入),2)=1;ZAI:=FILTER(VARF1ANDVARF2,2);VV2:=REF(CLOSE,1);VV3:=SMA((CLOSE-VV2),6,1)/SMA(Abs(CLOSE-VV2),6,1)*100;DRAWICON(REF(......
  • 通达信(分时副图)资金流向技术指标公式源码
     JLX:=IF(C>REF(C,1),AMOUNT,0);JLZ:=IF(C<REF(C,1),AMOUNT,0);总额:=SUM(AMOUNT,0)/1000000,NODRAW,COLORYELLOW;净流入:(SUM(JLX,0)-SUM(JLZ,0))/1000000,COLORRED,LINETHICK2;WA1:=V*C/100;WA2:=SUM((IF(((WA1/8>20)AND(CLOSE>(REF(CLOSE,1)))),WA1,0)),0);WA3:=......
  • 基于Java+Vue开发的企业Ehr数智化人力管理系统源码+配套文档(提升人力资源管理效率的利
    写在前面:随着企业规模的不断扩大和人力资源管理的日益复杂,传统的人力资源管理方式已经无法满足现代企业的需求。为了提高管理效率、优化资源配置、降低人力成本,越来越多的企业开始引入eHR人力资源管理系统。本文将重点介绍eHR系统在招聘管理、人事管理、考勤管理、绩效管理、社保......