5

我正在从事一个项目,其主要设计指导原则是可扩展性。

我通过定义一个元类来实现一个插件系统,该元类使用类方法注册任何加载的插件的类名(每种类型的插件都继承自核心代码中定义的特定类,因为有不同类型的插件在应用程序)。基本上这意味着开发人员必须将他的类定义为

class PieChart(ChartPluginAncestor):
    # Duck typing:
    # Implement compulsory methods for Plugins 
    # extending Chart functionality

并且主程序将知道他的存在,因为PieChart将包含在可用的注册插件列表中ChartPluginAncestor.plugins

作为类方法的挂载方法,所有插件在其类代码加载到内存时都会被注册(甚至在该类的对象被实例化之前)

该系统对我来说足够好™(尽管我总是对如何改进体系结构的建议持开放态度!)但我现在想知道管理插件文件的最佳方法是什么(即包含插件的文件在哪里以及如何应储存)。

到目前为止,我正在使用 - 出于开发目的 - 我称之为“插件”的包。我将所有包含插件类的 *.py 文件放在包目录中,我只是import plugins在 main.py 文件中发出,以便所有插件都能正确安装。

编辑:杰夫在评论中指出,import plugins包的各个模块中包含的类不会很容易获得(我没有意识到这一点 - 出于调试目的 - 分别导入每个类from plugins.myAI import AI)。

然而,这个系统只有在我开发和测试代码时才好用,因为:

  • 插件可能带有自己的单元测试,我不想将它们加载到内存中。
  • 所有插件当前都加载到内存中,但确实有某些插件是相同功能的替代版本,所以你真的只需要知道你可以在两者之间切换,但你只想加载你选择的那个从配置窗格。
  • 在某些时候,我会希望有一个安装插件的双重位置:一个系统范围的位置(例如在某处/usr/local/bin/)和一个特定于用户的位置(例如在某处/home/<user>/.myprogram/)。

所以我的问题真的是——也许——三个:

  1. 插件容器:我的目标最明智的选择是什么?单个文件?包?.py 文件的简单目录?)
  2. 识别插件的存在而不必加载(导入)它们:使用 Python 内省来做到这一点的聪明方法是什么?
  3. 将插件放置在两个不同的位置:是否有标准的方法/最佳实践(至少在 gnu/linux 下)可以做到这一点?
4

2 回答 2

3

这个问题很难解决,因为需求很复杂。无论如何,我会尝试一些建议。

关于

将插件放置在两个不同的位置:是否有标准的方法/最佳实践(至少在 gnu/linux 下)可以做到这一点?

一个好的方法是 virtualenv。Virtualenv 是一个用于构建“隔离”python 安装的 python 模块。这是让单独的项目一起工作的更好方法。您将获得一个全新的站点包,您可以在其中将插件与相关的项目模块一起放置。

试一试: http: //pypi.python.org/pypi/virtualenv

插件容器:我的目标最明智的选择是什么?单个文件?包?.py 文件的简单目录?)

一个好的方法是一个 python 包,它可以在导入时进行“自我注册”:只需在包目录中定义一个适当的init .py

一个示例可以是http://www.qgis.org/wiki/Writing_Python_Plugins 以及此处描述的 API http://twistedmatrix.com/documents/current/core/howto/plugin.html

另见http://pypi.python.org/pypi/giblets/0.2.1

Giblets 是一个基于 Trac 组件架构的简单插件系统。简而言之,giblets 允许您声明接口并发现实现它们而无需耦合的组件。

Giblets 还包括基于文件路径或入口点的插件发现以及管理应用程序中启用或禁用哪些组件的灵活方法。

于 2010-07-29T12:35:30.033 回答
1

我也有一个包含三种类型插件的插件系统,尽管我并没有声称它做得很好。你可以在这里看到一些细节。

对于内部插件,我有一个包(例如,MethodPlugins),并且在这个包中是每个插件的一个模块(例如,MethodPlugins.IRV)。这是我加载插件的方式:

  1. 加载包 ( import MethodPlugins)

  2. 用于pkgutil.iter_modules加载那里的所有模块(例如,MethodPlugins.IRV

  3. 所有插件都来自一个通用基类,因此我可以使用__subclassess__它们来识别它们。

我相信这将允许您在不实际加载它们的情况下识别插件,尽管我不这样做,因为我只是将它们全部加载。

对于外部插件,我有一个用户可以放置它们的指定目录,我os.listdir用来导入它们。用户需要使用正确的基类,这样我才能找到它们。

我也有兴趣改进它,但它对我来说也足够好。:)

于 2010-07-29T13:31:53.733 回答