Python 2.6 中的动态类加载:运行时警告:处理绝对导入时找不到父模块“插件”

StackOverflow https://stackoverflow.com/questions/2267984

我正在开发一个插件系统,其中插件模块的加载方式如下:

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)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top