【原文链接】Pluggy源码解读----PluginManager类的其他功能
至此pluggy的主要功能的源码基本都已经解读完了,这里在将PluginManager类中其他功能的代码在简要的解读一下,PluginManager类不但提供了注册插件的功能,还提供了取消注册插件的功能,取消注册插件的功能代码实现如下所示,注册的代码解读完成后再来看取消注册的代码就简单多了,取消注册简单点说就是_name2plugin属性中删除对应的插件,然后将_plugin2hookcallers属性中将对应插件中的所有注册的方法去除即可,当然在这个过程中,必然涉及到判断是否存在此插件等等。
def unregister(self, plugin=None, name=None):
"""unregister a plugin object and all its contained hook implementations
from internal data structures."""
if name is None:
assert plugin is not None, "one of name or plugin needs to be specified"
name = self.get_name(plugin)
if plugin is None:
plugin = self.get_plugin(name)
# if self._name2plugin[name] == None registration was blocked: ignore
if self._name2plugin.get(name):
del self._name2plugin[name]
for hookcaller in self._plugin2hookcallers.pop(plugin, []):
hookcaller._remove_plugin(plugin)
PluginManager还提供了设置阻塞的方法,代码如下,设置阻塞的代码就更简单了,直接调用取消注册的方法实现,然后将_name2plugin属性此插件名对应的值设置为None即可。
def set_blocked(self, name):
"""block registrations of the given name, unregister if already registered."""
self.unregister(name=name)
self._name2plugin[name] = None
下面是判断是否阻塞的代码实现,实质上就是判断插件名是否在_name2plugin属性中以及当_name2plugin属性中存在插件名时需要进一步判断此插件名对应的插件对象是否为None。
def is_blocked(self, name):
"""return ``True`` if the given plugin name is blocked."""
return name in self._name2plugin and self._name2plugin[name] is None
如下为获取插件列表的代码,这里直接将_plugin2hookcallers属性转换为集合然后返回。
def get_plugins(self):
"""return the set of registered plugins."""
return set(self._plugin2hookcallers)
如下代码为判断插件是否注册,即判断插件类对象是否在_plugin2hookcallers属性中。
def is_registered(self, plugin):
"""Return ``True`` if the plugin is already registered."""
return plugin in self._plugin2hookcallers
如下为根据插件名获取插件对象,这里直接从_name2plugin属性中根据名称获取即可,因为_name2plugin是一个字典格式数据。
def get_plugin(self, name):
"""Return a plugin or ``None`` for the given name."""
return self._name2plugin.get(name)
如下为判断是否有插件,则直接调用根据名称获取插件对象,只要返回的插件对象不为None即可。
def has_plugin(self, name):
"""Return ``True`` if a plugin with the given name is registered."""
return self.get_plugin(name) is not None
如下是一个很重要的,可以通过指定group名称的方式来自动注册插件,只要当前的环境中其他包中有通过setuptools的方式定义了此group名称的模块,就可以自动的注册,在著名的自动化测试框架pytest中,就是使用了这个函数,对group为“pytest11”的插件进行自动注册,使用起来非常方便,这样用户就可以通过自定义pytest11模块来对pytest做功能增强了,而不需要修改pytest的源码
def load_setuptools_entrypoints(self, group, name=None):
"""Load modules from querying the specified setuptools ``group``.
:param str group: entry point group to load plugins
:param str name: if given, loads only plugins with the given ``name``.
:rtype: int
:return: return the number of loaded plugins by this call.
"""
count = 0
for dist in list(importlib_metadata.distributions()):
for ep in dist.entry_points:
if (
ep.group != group
or (name is not None and ep.name != name)
# already registered
or self.get_plugin(ep.name)
or self.is_blocked(ep.name)
):
continue
plugin = ep.load()
self.register(plugin, name=ep.name)
self._plugin_distinfo.append((plugin, DistFacade(dist)))
count += 1
return count
PluginManager类还有几个简单的方法,这里就不再一一分析了,至此对pluggy的源码分析就全部完成了。