我有一个用Python编写的应用程序,它是由相当专业的观众(科学家)使用的。

我正在寻找一个好方法,使应用程序可扩展的用户,即脚本/插件架构。

I am looking for something extremely lightweight. Most scripts, or plugins, are not going to be developed and distributed by a third-party and installed, but are going to be something whipped up by a user in a few minutes to automate a repeating task, add support for a file format, etc. So plugins should have the absolute minimum boilerplate code, and require no 'installation' other than copying to a folder (so something like setuptools entry points, or the Zope plugin architecture seems like too much.)

是否已经有类似的系统存在,或者是否有项目实现了类似的方案,我应该看看想法/灵感?


当前回答

module_example.py:

def plugin_main(*args, **kwargs):
    print args, kwargs

loader.py:

def load_plugin(name):
    mod = __import__("module_%s" % name)
    return mod

def call_plugin(name, *args, **kwargs):
    plugin = load_plugin(name)
    plugin.plugin_main(*args, **kwargs)

call_plugin("example", 1234)

它当然是“最小的”,它绝对没有错误检查,可能有无数的安全问题,它不是很灵活-但它应该告诉你一个Python插件系统可以多么简单。

你可能也想看看imp模块,尽管你可以用__import__, os。Listdir和一些字符串操作。

其他回答

当我在Python中搜索插件框架时,我花了时间阅读这篇文章。我用过一些,但有缺点。这是我在2017年为你提供的一个无接口、松散耦合的插件管理系统:稍后再加载我。这里有关于如何使用它的教程。

实际上,setuptools工作在一个“插件目录”下,下面的例子摘自项目文档: http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins

使用示例:

plugin_dirs = ['foo/plugins'] + sys.path
env = Environment(plugin_dirs)
distributions, errors = working_set.find_plugins(env)
map(working_set.add, distributions)  # add plugins+libs to sys.path
print("Couldn't load plugins due to: %s" % errors)

从长远来看,setuptools是一个更安全的选择,因为它可以加载插件而不会发生冲突或丢失需求。

另一个好处是插件本身可以使用相同的机制进行扩展,而无需原始应用程序关心它。

当我搜索Python Decorators时,发现了一个简单但有用的代码片段。它可能不符合你的需求,但非常鼓舞人心。

Scipy高级Python#插件注册系统

class TextProcessor(object):
    PLUGINS = []

    def process(self, text, plugins=()):
        if plugins is ():
            for plugin in self.PLUGINS:
                text = plugin().process(text)
        else:
            for plugin in plugins:
                text = plugin().process(text)
        return text

    @classmethod
    def plugin(cls, plugin):
        cls.PLUGINS.append(plugin)
        return plugin


@TextProcessor.plugin
class CleanMarkdownBolds(object):
    def process(self, text):
        return text.replace('**', '')

用法:

processor = TextProcessor()
processed = processor.process(text="**foo bar**", plugins=(CleanMarkdownBolds, ))
processed = processor.process(text="**foo bar**")

你也可以看看“基础工作”。

其思想是围绕可重用组件(称为模式和插件)构建应用程序。插件是派生自GwBasePattern的类。 这里有一个基本的例子:

from groundwork import App
from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs):
        self.name = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self): 
        pass

    def deactivate(self):
        pass

my_app = App(plugins=[MyPlugin])       # register plugin
my_app.plugins.activate(["My Plugin"]) # activate it

还有更高级的模式来处理命令行接口、信号或共享对象。

foundation可以通过编程方式将插件绑定到应用程序中,如上面所示,也可以通过setuptools自动查找插件。包含插件的Python包必须使用一个特殊的入口点groundwork.plugin声明这些插件。

这是文件。

免责声明:我是《基础》的作者之一。

module_example.py:

def plugin_main(*args, **kwargs):
    print args, kwargs

loader.py:

def load_plugin(name):
    mod = __import__("module_%s" % name)
    return mod

def call_plugin(name, *args, **kwargs):
    plugin = load_plugin(name)
    plugin.plugin_main(*args, **kwargs)

call_plugin("example", 1234)

它当然是“最小的”,它绝对没有错误检查,可能有无数的安全问题,它不是很灵活-但它应该告诉你一个Python插件系统可以多么简单。

你可能也想看看imp模块,尽管你可以用__import__, os。Listdir和一些字符串操作。