测试开发技术网站
博客
设计
设计
开发
Python
测试
unittest
运维
Linux基础应用
CI/CD
CI/CD
数据库
数据库
云计算
云计算
云原生
云原生
爬虫
爬虫
数据分析
数据分析
人工智能
人工智能
登录
注册
Pluggy源码解读----add_hookspecs增加自定义的接口类
收藏本文
作者:redrose2100 类别: 日期:2022-12-10 06:44:38 阅读:843 次 消耗积分:0 分
[TOC] ![](https://redrose2100.oss-cn-hangzhou.aliyuncs.com/img/7cd47362-951c-11ee-986a-0242ac110004.png) 在应用中,add_hookspecs的应用代码如下,即将MySpec类作为参数传递给add_hookspecs方法。 ```python pm.add_hookspecs(MySpec) ``` add_hookspecs方法的定义如下,因此这里形参module_or_class即是MySpec类,因此这里的for循环,相当于是遍历MySpec类的方法和属性。从最外层的for循环和与for循环同层级的if语句可以看出,for循环就是通过对传进来的MySpec类的方法和属性进行遍历,对于符合要求的放入names列表,最后判断如果names为空,即没有找到符合要求的方法或属性,则抛出一个异常,而到底什么样的才是符合要求的,则需继续分析spec_opts变量获取到的值。 ```python def add_hookspecs(self, module_or_class): """add new hook specifications defined in the given ``module_or_class``. Functions are recognized if they have been decorated accordingly.""" names = [] for name in dir(module_or_class): spec_opts = self.parse_hookspec_opts(module_or_class, name) if spec_opts is not None: hc = getattr(self.hook, name, None) if hc is None: hc = _HookCaller(name, self._hookexec, module_or_class, spec_opts) setattr(self.hook, name, hc) else: # plugins registered this hook without knowing the spec hc.set_specification(module_or_class, spec_opts) for hookfunction in hc.get_hookimpls(): self._verify_hook(hc, hookfunction) names.append(name) if not names: raise ValueError( f"did not find any {self.project_name!r} hooks in {module_or_class!r}" ) ``` spec_opts变量是通过parse_hookspec_opts方法来获取值的,而此方法的实现如下,这里看出来,首先是根据方法或属性名获取到方法或属性对象,然后将该对象的myproject_spec属性的值返回,通过前面解析HookspecMarker类的时候我们知道,在定义MySpec类中的myhook方法是使用了一个装饰器,而此装饰器就是增加myproject_spec属性的。至此就得到了对应,因此,parse_hookspec_opts方法作用就很明显了,即获取对象的myproject_spec属性的值,如果没有此属性,则返回None ```python def parse_hookspec_opts(self, module_or_class, name): method = getattr(module_or_class, name) return getattr(method, self.project_name + "_spec", None) ``` 再返回到add_hookspecs方法,这里可以看到,如果spec_opts是None的话,直接跳过了,只有spec_opts不是None的时候才进行进一步的处理,换句话说就是MySpec的所有的方法和属性中,只有被hookspec装饰器装饰了的函数,才进行进一步处理,而在前面也已经分析过,MySpec类中myhook方法使用了装饰器后,就拥有了myproject_spec属性,属性值是一个字典。而且字典中拥有firstresult,historic,warn_on_impl三个key,下面hc变量通过从self.hook对象中取myhook属性,在PluginManager类初始化的时候,我们知道,self.hook被初始化为_HookRelay类的一个实例,但是此类没有定义任何属性和方法,因此这里的hc显然为None,接下来可以看到当hc为None时,hc则给初始化为_HookCaller类的一个实例,_HookCaller类的初始化实现代码如下,那么可以看到,这里的name就是注册的接口名myhook,这里的_hookexec就是PluginManager类中的_inner_hookexec也就是_multicall函数,而specmodule_or_class则是传递进来的MySpec类,显然不是None,以你次又继续调用specification方法。 ```python class _HookCaller: def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None): self.name = name self._wrappers = [] self._nonwrappers = [] self._hookexec = hook_execute self._call_history = None self.spec = None if specmodule_or_class is not None: assert spec_opts is not None self.set_specification(specmodule_or_class, spec_opts) ``` set_specification方法定义代码如下,这里相当于是给_HookCaller类的spec属性赋值了一个HookSpec类的实例化对象,而且判断spec_opts中historic是否为True,如果为True,则将_HookCaller类的_call_history属性初始化为空列表。 ```python def set_specification(self, specmodule_or_class, spec_opts): assert not self.has_spec() self.spec = HookSpec(specmodule_or_class, self.name, spec_opts) if spec_opts.get("historic"): self._call_history = [] ``` HookSpec类的定义如下,这里可以理解为一个原子类型的类了,即此类中namespace是MySpec类,name则是定义的接口名myhook,function则是myhook方法对象,opts则是包含firstresult,historic,warn_on_impl三个key字典,argnames和kwargnames则是myhook函数的参数,warn_on_impl则是opts中的warn_on_impl属性值。 ```python class HookSpec: def __init__(self, namespace, name, opts): self.namespace = namespace self.function = function = getattr(namespace, name) self.name = name self.argnames, self.kwargnames = varnames(function) self.opts = opts self.warn_on_impl = opts.get("warn_on_impl") ``` 再回到add_hookspecs方法中,即此时hc已经赋值了,即hc是_HookCaller类的一个实例对象,然后下面一行代码怎是self.hook设置一个属性和值了,即是给_HookRelay类的实例对象self.hook设置属性myhook,值为hc对象。 ```python setattr(self.hook, name, hc) ``` 当然如果hc不为空,则直接更新属性了。 至此,add_hookspecs方法就分析完成了。
始终坚持开源开放共享精神,同时感谢您的充电鼓励和支持!
版权所有,转载本站文章请注明出处:redrose2100, http://blog.redrose2100.com/article/492
上一篇:
Pluggy源码解读----PluginManager类实例化
下一篇:
Pluggy源码解读----register注册插件源码解析
搜索
个人成就
出版书籍
《Pytest企业级应用实战》
测试开发技术全栈公众号
测试开发技术全栈公众号
DevOps技术交流微信群
加微信邀请进群
常用网站链接
开源软件洞察
云原生技术栈全景图
Python语言官方文档
Golang官方文档
Docker官方文档
Jenkins中文用户手册
Scrapy官方文档
VUE官方文档
Harbor官方文档
openQA官方文档
云原生开源社区
开源中国
Kubernetes中文文档
Markdown语法官方教程
Kubernetes中文社区
Kubersphere官方文档
BootStrap中文网站
JavaScript中文网
NumPy官方文档
Pandas官方文档
GitLink确实开源网站
数据库排名网站
编程语言排名网站
SEO综合查询网站
数学加减法练习自动生成网站
Kickstart Generator
文章分类
最新文章
最多阅读
特别推荐
×
Close
登录
注册
找回密码
登录邮箱:
登录密码:
图片验证码:
注册邮箱:
注册密码:
邮箱验证码:
发送邮件
注册邮箱:
新的密码:
邮箱验证码:
发送邮件