stevedore是用来实现动态加载代码的开源模块。它是在OpenStack中用来加载插件的公共模块。可以独立于OpenStack而安装使用:https://pypi.python.org/pypi/stevedore/
stevedore使用setuptools的entry points来定义并加载插件。entry point引用的是定义在模块中的对象,比如类、函数、实例等,只要在import模块时能够被创建的对象都可以。
一:插件的名字和命名空间
一般来讲,entry point的名字是公开的,用户可见的,经常出现在配置文件中。而命名空间,也就是entry point组名却是一种实现细节,一般是面向开发者而非最终用户的。可以用Python的包名作为entry point命名空间,以保证唯一性,但这不是必须的。
entry points的主要特征就是,它可以是独立注册的,也就是说插件的开发和安装可以完全独立于使用它的应用,只要开发者和使用者在命名空间和API上达成一致即可。
命名空间被用来搜索entry points。entry points的名字在给定的发布包中必须是唯一的,但在一个命名空间中可以不唯一。也就是说,同一个发布包内不允许出现同名的entry point,但是如果是两个独立的发布包,却可以使用完全相同的entrypoint组名和entry point名来注册插件。
二:插件的使用方式
在stevedore中,有三种使用插件的方式:Drivers、Hooks、Extensions
1:Drivers
一个名字对应一个entry point。使用时根据插件的命名空间和名字,定位到单独的插件:
2:Hooks,一个名字对应多个entry point。允许同一个命名空间中的插件具有相同的名字,根据给定的命名空间和名字,加载该名字对应的多个插件。
3:Extensions,多个名字,多个entry point。给定命名空间,加载该命名空间中所有的插件,当然也允许同一个命名空间中的插件具有相同的名字。
三:定义并注册插件
在经过了大量的试验和总结教训之后,发现定义API最简单的方式是遵循下面的步骤:
a:使用abc模块,创建一个抽象基类来定义插件API的行为;虽然开发者无需继承一个基类,但是这种方式自有它的好处;
b:通过继承基类并实现必要的方法来创建插件
c:为每个API定义一个命名空间。可以将应用或者库的名字,以及API的名字结合起来,这种方式通俗易懂,如 “cliff.formatters”或“ceilometer.pollsters.compute”。
本节例子中创建的插件,用来对数据进行格式化输出,每个格式化方法接受一个字典作为输入,然后按照一定的规则产生要输出的字符串。格式化类可以有一个最大输出宽度的参数。
1:首先定义一个基类,其中的API需要由插件来实现
# example/pluginbase.py
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class FormatterBase(object):
"""Base class for example plugin used in the tutorial."""
def __init__(self, max_width=60):
self.max_width = max_width
@abc.abstractmethod
def format(self, data):
"""Format the data and return unicode text.
:param data: A dictionary with string keys and simple types as
values.
:type data: dict(str:?)
:returns: Iterable producing the formatted text.
"""
2:定义插件1