Python 2.6 中的动态类加载:运行时警告:处理绝对导入时找不到父模块“插件”
-
20-09-2019 - |
题
我正在开发一个插件系统,其中插件模块的加载方式如下:
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
该代码有效,但对于插件代码中的每个导入语句,我都会收到如下警告:
plugins/plugin.py:2: RuntimeWarning: Parent module 'plugins' not found while handling absolute import
import os
主程序代码没有报告错误,并且插件可以工作。
有人可以解释一下警告的含义以及我做错了什么吗?我是否需要单独创建一个空的插件模块并导入它以使 python 满意?
解决方案
如果该目录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
不过是黑客工具,主要是为了好玩!
其他提示
如果插件目录上没有 __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
.如果你不打算做什么理智的响应的一个例外,你的节目不能去三立.
这里的问题是与点(“”)在模块名称:
imp.load_module('plugins.'+name, f, file, desc)
不要包含“”后“插件”,或Python将认为这是一个模块的路径。
您可以尝试在import语句的开头添加以下语句。
from __future__ import absolute_import
蟒蛇 imp
自回答此问题以来,文档已更新。现在它专门解决了这个问题 find_module()
方法。
此函数不处理分层模块名称(名称包含点)。为了找到 下午, ,即子模块 中号 包装数量 磷, , 使用
find_module()
和load_module()
查找并加载包 磷, ,然后使用find_module()
与 小路 参数设置为P.__path__
. 。什么时候 磷 本身有一个点名称,递归地应用这个配方。
注意 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)