Python3 插件系统

2 投票
3 回答
2085 浏览
提问于 2025-04-17 08:39

我正在尝试创建一个类似于yapsy的插件框架(可惜yapsy不支持python3)。

我的代码看起来是这样的:

root
   main.py
   plugins/
       __init__.py
       PluginManager.py
       UI/
           __init__.py
           textui.py

在PluginManager.py文件中,我定义了以下类:

class PluginMetaclass(type):
    def __init__(cls, name, base, attrs):
        if not hasattr(cls, 'registered'):
            cls.registered = []
        else:
            cls.registered.append((name,cls))

class UI_Plugins(object):
    __metaclass__ = PluginMetaclass

    #...some code here....

    def load():
         #...some code here too...

        if "__init__" in  os.path.basename(candidate_filepath):
            sys.path.append(plugin_info['path'])
        try:
            candidateMainFile = open(candidate_filepath+".py","r")  
            exec(candidateMainFile,candidate_globals)
        except Exception as e:
            logging.error("Unable to execute the code in plugin: %s" % candidate_filepath)
            logging.error("\t The following problem occured: %s %s " % (os.linesep, e))
            if "__init__" in  os.path.basename(candidate_filepath):
                sys.path.remove(plugin_info['path'])
            continue

其中candidate_filepath包含插件的路径。

textui.py文件包含以下内容:

from root.plugins.PluginManager import UI_Plugins

class TextBackend(UI_Plugins):
    def run(self):
        print("c")

当我尝试加载插件时,我遇到了这个错误:

No module named plugins.PluginManager 

我该如何解决这个问题呢?

3 个回答

1
  1. 要创建一个包,你需要在一个文件夹里放一个叫做 __init__.py 的文件。这个文件可以是空的,但必须存在,而且在“根目录”和“插件目录”里都要有。
  2. 文件夹的名字就是命名空间的名字,所以它们必须完全一致。在你的情况下,你需要使用 from root.plugin.PluginManager import UI_Plugins 这个语句。
  3. 最后,为了让导入功能正常工作,这个包必须在你的 PYTHONPATH 中(可以查看 模块搜索路径,这是官方文档)。你可以通过将这个文件夹添加到 PYTHONPATH 环境变量中来实现,或者在代码里把它加到 sys.path 列表中。
5

抱歉,这个回答可能不是你问题的直接答案,但如果你想开发一个类似于yapsy的东西,特别是针对python3的版本,那么你可能会对yapsy的新版本感兴趣。在这个新版本中,我发布了一些兼容python3的包:

https://sourceforge.net/projects/yapsy/files/Yapsy-1.9/

(可以查看 Yapsy-1.9_python3-py3.2.egg 或 Yapsy-1.9-python3.tar.gz)

源代码在一个特定的分支上:

http://yapsy.hg.sourceforge.net/hgweb/yapsy/yapsy/file/91ea058181ee

2

导入语句

from root.plugins.PluginManager import UI_Plugins

不管用,因为 root 不是一个包。

不过,如果应用程序是用

python3 root/main.py

启动的,那么 root 实际上就 不需要 是一个包。

你只需要把 textui.py 中的导入语句改成

from plugins.PluginManager import UI_Plugins

这样就可以正常工作了。

之所以这样可以工作,是因为当前运行的脚本所在的目录会自动加到 sys.path 的最前面。在你的情况中,这个目录就是 root,而且因为 plugins 是这个目录下的一个包,所以你可以在应用程序的任何地方直接导入它。因此,只要你的 main 脚本保持在原来的位置,就不需要做其他路径的调整了。

撰写回答