Python 2.6 中的动态类加载:RuntimeWarning:处理绝对导入时未找到父模块“插件”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2267984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamic class loading in Python 2.6: RuntimeWarning: Parent module 'plugins' not found while handling absolute import
提问by pehrs
I am working on a plugin system where plugin modules are loaded like this:
我正在开发一个插件系统,其中插件模块是这样加载的:
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
The code works, but for each import statement in the plugin code i get a warning like this:
该代码有效,但对于插件代码中的每个导入语句,我都会收到如下警告:
plugins/plugin.py:2: RuntimeWarning: Parent module 'plugins' not found while handling absolute import
import os
No errors are reported for the main program code, and the plugins work.
主程序代码没有错误报告,插件工作。
Can somebody explain what the warning means and what I doing wrong. Do I need to create an empty plugins module separately and import it to keep python happy?
有人可以解释警告的含义以及我做错了什么。我是否需要单独创建一个空的插件模块并导入它以使 python 开心?
采纳答案by u0b34a0f6ae
If the directory plugins
were a real package (contained __init__.py
fine), you could easily use pkgutils to enumerate its plugin files and load them.
如果目录plugins
是一个真正的包(包含__init__.py
很好),您可以轻松地使用 pkgutils 枚举其插件文件并加载它们。
import pkgutil
# import our package
import plugins
list(pkgutil.iter_modules(plugins.__path__))
However, it can work without a plugin package anyway, try this:
但是,无论如何它都可以在没有插件包的情况下工作,试试这个:
import pkgutil
list(pkgutil.iter_modules(["plugins"]))
Also it is possible to make a package that only exists at runtime:
也可以制作一个只在运行时存在的包:
import types
import sys
plugins = types.ModuleType("plugins")
plugins.__path__ = ["plugins"]
sys.modules["plugins"] = plugins
import plugins.testplugin
However that hack that was mostly for fun!
然而,那个黑客主要是为了好玩!
回答by Mike Graham
If the plugins directory does not have an __init__.py
, it isn't a package, so when you create plugins.whatever
, Python warns you that such a thing shouldn't really exist. (It couldn't be created by "import plugins.whatever
" no matter what your path is.)
如果 plugins 目录没有__init__.py
,则它不是包,因此当您创建 时plugins.whatever
,Python 会警告您这种东西不应该真的存在。(import plugins.whatever
无论你的路径是什么,它都不能由“ ”创建。)
Also,
还,
- Don't split on
/
, which is unportable. Useos.path.split
. - Don't use
.split(".py")
to get the name without the extension, which is buggy. Useos.path.splitext
. - Don't use
getattr
with a string literal.getattr(plugin, "__init__")
is spelledplugin.__init__
. - I am confused why you are calling a module-level
__init__
function. This doesn't seem right. Perhaps you want a "set_logger" function or better, to instantiate a class that takes a logger. - Don't use
L = L + some_other_list
to extend a list, use theextend
method, which has better performance and is more idiomatic. - Don't squash unknown exceptions by
except Exception
. If you cannot plan to do something sane in response to an exception, your program cannot go on sanely.
- 不要拆分
/
,这是不可移植的。使用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
. 如果你不能计划做一些理智的事情来应对异常,你的程序就不能理智地进行。
回答by Ferry Boender
The problem here is with the dot ('.') in the module name:
这里的问题在于模块名称中的点 ('.'):
imp.load_module('plugins.'+name, f, file, desc)
imp.load_module('plugins.'+name, f, file, desc)
Don't include a '.' after 'plugins', or Python will think it's a module path.
不要包含“.” 在“插件”之后,否则 Python 会认为它是一个模块路径。
回答by Vitz
You can try adding below statement at the beginning of import statements.
您可以尝试在导入语句的开头添加以下语句。
from __future__ import absolute_import
回答by Mark Mikofski
The Python imp
documentation has been updated since this was answered. It now addresses this issue specifically in the find_module()
method.
imp
自从回答这个问题以来,Python文档已经更新。现在它在find_module()
方法中专门解决了这个问题。
This function does not handle hierarchical module names (names containing dots). In order to find P.M, that is, submodule Mof package P, use
find_module()
andload_module()
to find and load package P, and then usefind_module()
with the pathargument set toP.__path__
. When Pitself has a dotted name, apply this recipe recursively.
此函数不处理分层模块名称(包含点的名称)。为了找到PM,即包P 的子模块M,使用和来查找和加载包P,然后在路径参数设置为 的情况下使用。当P本身有一个带点的名字时,递归地应用这个配方。
find_module()
load_module()
find_module()
P.__path__
Note that P.__path__
is already a list when supplying it to find_module()
. Also note what the find_module()
documentation says about finding packages.
请注意,P.__path__
将其提供给 时已经是一个列表find_module()
。还要注意find_module()
文档中关于查找包的内容。
If the module is a package, fileis
None
, pathnameis the package path and the last item in the descriptiontuple isPKG_DIRECTORY
.
如果模块是包,则文件是
None
,路径名是包路径,描述元组中的最后一项是PKG_DIRECTORY
。
So from the OP's question, to import the plugin without the RuntimeError
warnings, follow the directions in the updated Python documentation:
因此,根据 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)