我正在开发一个插件系统,插件模块的加载方式如下:
def load_plugins():
plugins=glob.glob("plugins/*.py")
instances=[]
for p in plugins:
try:
name=p.split("/")[-1]
name=name.split(".py")[0]
log.debug("Possible plugin: %s", name)
f, file, desc=imp.find_module(name, ["plugins"])
plugin=imp.load_module('plugins.'+name, f, file, desc)
getattr(plugin, "__init__")(log)
instances=instances+plugin.get_instances()
except Exception as e:
log.info("Failed to load plugin: "+str(p))
log.info("Error: %s " % (e))
log.info(traceback.format_exc(e))
return instances
代码有效,但对于插件代码中的每个import语句,我都会收到如下警告:
plugins/plugin.py:2: RuntimeWarning: Parent module 'plugins' not found while handling absolute import
import os
没有报告主程序代码的错误,插件也能正常工作。
有人可以解释警告意味着什么以及我做错了什么。我是否需要单独创建一个空的插件模块并导入它以保持python的快乐?
答案 0 :(得分:16)
如果plugins目录没有__init__.py
,那么它不是包,所以当你创建plugins.whatever
时,Python会警告你这样的事情不应该存在。 (无论您的路径是什么,都无法通过“import plugins.whatever
”创建。)
此外,
/
,这是不可移植的。使用os.path.split
。.split(".py")
来获取没有扩展名的名称,这是错误的。使用os.path.splitext
。getattr
与字符串文字一起使用。 getattr(plugin, "__init__")
的拼写为plugin.__init__
。__init__
函数。这似乎不对。也许您想要一个“set_logger”函数或更好的函数来实例化一个带记录器的类。L = L + some_other_list
扩展列表,请使用extend
方法,该方法具有更好的性能且更具惯用性。except Exception
压缩未知的例外情况。如果你不能计划在异常情况下做一些理智的事情,那么你的计划就无法顺利进行。答案 1 :(得分:14)
如果目录plugins
是真正的包(包含__init__.py
),您可以轻松使用pkgutils枚举其插件文件并加载它们。
import pkgutil
# import our package
import plugins
list(pkgutil.iter_modules(plugins.__path__))
但是,无论如何它都可以在没有插件包的情况下工作,试试这个:
import pkgutil
list(pkgutil.iter_modules(["plugins"]))
还可以创建仅在运行时存在的包:
import types
import sys
plugins = types.ModuleType("plugins")
plugins.__path__ = ["plugins"]
sys.modules["plugins"] = plugins
import plugins.testplugin
然而,黑客主要是为了好玩!
答案 2 :(得分:6)
这里的问题是模块名称中的点('。'):
imp.load_module('plugins.'+name, f, file, desc)
不要包含'。'在“插件”之后,或者Python会认为它是一个模块路径。
答案 3 :(得分:2)
您可以尝试在import语句的开头添加以下语句。
from __future__ import absolute_import
答案 4 :(得分:0)
Python imp
文档已经更新,因为已经得到了解答。它现在特别在find_module()
方法中解决了这个问题。
此功能不处理分层模块名称(包含点的名称)。要查找 PM ,即包 P 的子模块 M ,请使用
find_module()
和load_module()
查找并加载包 P ,然后使用find_module()
并将路径参数设置为P.__path__
。当 P 本身具有虚线名称时,请递归应用此配方。
请注意,P.__path__
在将其提供给find_module()
时已经是一个列表。另请注意find_module()
文档中有关查找包的内容。
如果模块是包,文件是
None
,路径名是包路径和描述中的最后一项元组是PKG_DIRECTORY
。
从OP的问题来看,要导入没有RuntimeError
警告的插件,请按照更新的Python文档中的说明进行操作:
# first find and load the package assuming it is in
# the current working directory, '.'
f, file, desc = imp.find_module('plugins', ['.'])
pkg = imp.load_module('plugins', f, file, desc)
# then find the named plugin module using pkg.__path__
# and load the module using the dotted name
f, file, desc = imp.find_module(name, pkg.__path__)
plugin = imp.load_module('plugins.' + name, f, file, desc)