pytest系列——pluggy插件源码解读(二)PluginManager类实例化

PluginManager类简介

首先还是把pluggy的小例子放在这:

importpluggy# HookspecMarker 和 HookimplMarker 实质上是一个装饰器带参数的装饰器类,作用是给函数增加额外的属性设置hookspec = pluggy.HookspecMarker("myproject")hookimpl = pluggy.HookimplMarker("myproject")# 定义自己的Spec,这里可以理解为定义接口类classMySpec:# hookspec 是一个装饰类中的方法的装饰器,为此方法增额外的属性设置,这里myhook可以理解为定义了一个接口    @hookspecdefmyhook(self, arg1, arg2):pass# 定义了一个插件classPlugin_1:# 插件中实现了上面定义的接口,同样这个实现接口的方法用 hookimpl装饰器装饰,功能是返回两个参数的和    @hookimpldefmyhook(self, arg1, arg2):print("inside Plugin_1.myhook()")returnarg1 + arg2# 定义第二个插件classPlugin_2:# 插件中实现了上面定义的接口,同样这个实现接口的方法用 hookimpl装饰器装饰,功能是返回两个参数的差    @hookimpldefmyhook(self, arg1, arg2):print("inside Plugin_2.myhook()")returnarg1 - 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)

从上面的使用代码可以看出,通过HookspecMarker类和HookimplMarker实例化了两个对象,通过源码解读(1)知道,这两个实例实质上是两个装饰器,装饰器的作用是给函数设置一个名称为”{project_name}_spec”和”{project_name}_impl”属性

紧接着就是定义的子集的Spec类了,这个类实质上类似于面向对象编程中的定义接口,相当于在这个类中可以定义好许多接口(方法),即只要将自定义的Spec类中的方法加上@hookspec即相当于成为了插件的接口

然后即可以开始定义插件类了,插件类当然需要去对接口类中定义的方法去做接口的实现,即实现接口在不同的插件中的具体功能实现,即在插件中对方法加上@hookimpl装饰即相当于就约定好了是接口的实现(理解上可以这么理解,具体实现后面都会讲到)

紧接着就是到了PluginManager类的实例化了,这个类是pluggy模块中最最核心的一个类,它相当于pluggy的中枢大脑,pluggy的所有动作指令都是从这个类中发出的,这个类的是在manager.py文件中定义的

下面就是PluginManager类的初始化函数的源码(这个类还有很多功能代码,这里先只讲初始化,所以先只放这一小段源码)

classPluginManager:""" Core :py:class:`.PluginManager` class which manages registration

    of plugin objects and 1:N hook calling.

    You can register new hooks by calling :py:meth:`add_hookspecs(module_or_class)

    <.PluginManager.add_hookspecs>`.

    You can register plugin objects (which contain hooks) by calling

    :py:meth:`register(plugin) <.PluginManager.register>`.  The :py:class:`.PluginManager`

    is initialized with a prefix that is searched for in the names of the dict

    of registered plugin objects.

    For debugging purposes you can call :py:meth:`.PluginManager.enable_tracing`

    which will subsequently send debug information to the trace helper.

    """def__init__(self, project_name):        self.project_name = project_name        self._name2plugin = {}        self._plugin2hookcallers = {}        self._plugin_distinfo = []        self.trace = _tracing.TagTracer().get("pluginmanage")        self.hook = _HookRelay()        self._inner_hookexec = _multicall

PluginManager 类实例化的时候主要是初始化了几个变量:

project_name 可以理解为项目名称

_name2plugin 是一个字典,主要用于存放插件名称和插件对象的映射关系

_plugin2hookcallers 是也是一个字典,主要用于存放插件对象和插件对象对应的调用钩子函数的映射关系

_plugin_distinfo 是一个列表,用来存放通过setuptools注册的插件的信息

hook 是 _HookRelay类的实例,这个类的代码在hooks.py文件中,这个是一个空类,目的是用于存放hook函数的,所以主要用在后面注册插件的时候给这个空类的实例加设置属性的

_HookRelay 类的源代码如下:

class_HookRelay:""" hook holder object for performing 1:N hook calls where N is the number

    of registered plugins.

    """

_inner_hookexec 是一个函数,即是_multicall,这个函数的代码在callers.py文件中,这函数是整个pluggy插件模块最最核心的一个函数,所有的被注册的插件中的接口的执行顺序以及结果返回等等逻辑都在这个函数中

_multicall 的代码如下,这里先暂时不分析这个函数,现在只要知道_inner_hookexec属性其实就是_multicall这个函数即可

def_multicall(hook_name, hook_impls, caller_kwargs, firstresult):"""Execute a call into multiple python functions/methods and return the

    result(s).

    ``caller_kwargs`` comes from _HookCaller.__call__().

    """__tracebackhide__ =Trueresults = []    excinfo =Nonetry:# run impl and wrapper setup functions in a loopteardowns = []try:forhook_implinreversed(hook_impls):try:                    args = [caller_kwargs[argname]forargnameinhook_impl.argnames]exceptKeyError:forargnameinhook_impl.argnames:ifargnamenotincaller_kwargs:raiseHookCallError("hook call must provide argument %r"% (argname,)                            )ifhook_impl.hookwrapper:try:                        gen = hook_impl.function(*args)next(gen)# first yieldteardowns.append(gen)exceptStopIteration:                        _raise_wrapfail(gen,"did not yield")else:                    res = hook_impl.function(*args)ifresisnotNone:                        results.append(res)iffirstresult:# halt further impl callsbreakexceptBaseException:            excinfo = sys.exc_info()finally:iffirstresult:# first result hooks return a single valueoutcome = _Result(results[0]ifresultselseNone, excinfo)else:            outcome = _Result(results, excinfo)# run all wrapper post-yield blocksforgeninreversed(teardowns):try:                gen.send(outcome)                _raise_wrapfail(gen,"has second yield")exceptStopIteration:passreturnoutcome.get_result()

至此,PluginManager类的实例化流程就完成了

【功能测试到测试开发的全套教程+各种模板以及工具安装包获取:点击下方推荐的视频即可获取】

----------------------------------------------------------------------------------------------

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

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

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

测试开发相关教程推荐

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

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

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

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容