如何组织我已经工作的插件系统的文件结构?

时间:2010-07-29 06:51:00

标签: python plugins introspection software-design file-management

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

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

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

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

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

系统对我来说足够好™(虽然我总是乐于接受如何改进架构的建议!)但我现在想知道管理插件文件的最佳方法是什么(即应该存储包含插件的文件的位置和方式)。

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

编辑:杰夫在评论中指出import plugins包的各个模块中包含的类将不会随时可用(我没有意识到这一点 - 我是 - 出于调试目的 - 使用from plugins.myAI import AI分别导入每个类。

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

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

所以我的问题确实 - 或许 - 三:

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

2 个答案:

答案 0 :(得分:3)

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

关于

  

将插件分为两种不同的插件   位置:有标准方式/   最佳实践(在gnu / linux下,at   至少)这样做?

一个好的方法是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还包括插件发现   基于文件路径或入口点   以及灵活的管理手段   哪些组件已启用或   在您的申请中被禁用。

答案 1 :(得分:1)

我还有一个插件系统有三种类型的插件,但我并没有声称已经做得很好。您可以看到一些详细信息here

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

  1. 加载包裹(import MethodPlugins

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

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

  4. 我相信这可以让你识别插件而不会实际加载它们,虽然我不这样做,因为我只是加载它们。

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

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