我已经厌倦了在使用命名空间包并将代码库划分为单独的文件夹时,pylint无法导入文件的问题。因此,我开始深入研究astNG源代码,该代码已被确定为麻烦的来源(参见astng上的bugreport 8796)。这个问题的核心似乎是在寻找进口的过程中使用蟒蛇拥有imp.find_module
。
导入的第一个(子)包 - a
中的import a.b.c
- 会以find_module
路径传送到None
。无论路径返回什么路径,都会在查找循环中的下一个传递中输入find_module
,您在上一个示例中尝试查找b
。
来自logilab.common.modutils的伪代码:
path = None
while import_as_list:
try:
_, found_path, etc = find_module(import_as_list[0], path)
#exception handling and checking for a better version in the .egg files
path = [found_path]
import_as_list.pop(0)
这就是坏了:你只能获得find_module
的第一个最佳点击,它可能包含或不包含你的子包。如果您没有找到子包,则无法退出并尝试下一个。
我尝试使用sys.path而不是None,因此可以从路径列表中删除结果并进行第二次尝试,但python的模块查找器非常聪明,不必完全匹配在这些路径中,无论如何都要使这种方法无法使用 -
是否有替代find_modules会返回所有可能的匹配项或采取排除列表?我也对完全不同的解决方案持开放态度。最好不要手工修补python,但这不是不可能的 - 至少对于本地解决方案而言。
(警告:我正在运行python 2.6并且由于当前公司政策的原因无法升级,对p3k等的建议不会被标记为已被接受,除非它是唯一的答案。)
答案 0 :(得分:4)
从Python 2.5开始,正确的方法是使用pkgutil.iter_modules()(对于平面列表)或pkgutil.walk_packages()(对于子包树)。两者都与命名空间包完全兼容。
例如,如果我只想找到'jmb'的子包/子模块,我会这样做:
import jmb, pkgutil
for (module_loader, name, ispkg) in pkgutil.iter_modules(jmb.__path__, 'jmb.'):
# 'name' will be 'jmb.foo', 'jmb.bar', etc.
# 'ispkg' will be true if 'jmb.foo' is a package, false if it's a module
您还可以使用iter_modules或walk_packages在sys.path上遍历所有模块;有关详细信息,请参阅上面链接的文档。
答案 1 :(得分:2)
我也厌倦了PyLint中的这个限制。
我不知道替换imp.find_modules(),但我想我找到了另一种处理PyLint中命名空间包的方法。请参阅我对您链接的错误报告的评论(http://www.logilab.org/ticket/8796)。
我们的想法是使用pkg_resources来查找命名空间包。这是logilab.common.modutils._module_file()
之后的while modpath
添加内容:
while modpath:
if modpath[0] in pkg_resources._namespace_packages and len(modpath) > 1:
module = sys.modules[modpath.pop(0)]
path = module.__path__
这不是很精致,只能处理顶级命名空间包。
答案 2 :(得分:0)
警告+免责声明:尚未测试!
之前:
for part in parts:
modpath.append(part)
curname = '.'.join(modpath)
# ...
if module is None:
mp_file, mp_filename, mp_desc = imp.find_module(part, path)
module = imp.load_module(curname, mp_file, mp_filename, mp_desc)
for part in parts:
modpath.append(part)
curname = '.'.join(modpath)
# ...
if module is None:
# + https://stackoverflow.com/a/14820895/611007
# # mp_file, mp_filename, mp_desc = imp.find_module(part, path)
# # module = imp.load_module(curname, mp_file, mp_filename, mp_desc)
import pkgutil
mp_file = None
for loadr,name,ispkg in pkgutil.iter_modules(path=path,prefix='.'.join(modpath[:-1])+'.'):
if name.split('.')[-1] == part:
if not hasattr(loadr,'path') and hasattr(loadr,'archive'):
# with zips `name` was like '.somemodule'
# it gives `RuntimeWarning: Parent module '' not found while handling absolute import`
# I expect the name I need to be 'somemodule'
# TODO: I don't know why python does this or what the correct usage is.
# https://stackoverflow.com/questions/2267984/
if name and name[0] == '.':
name = name[1:]
ldr= loadr.find_module(name,loadr.archive)
module = ldr.load_module(name)
break
imploader= loadr.find_module(name,loadr.path)
mp_file,mp_filename,mp_desc= imploader.file,imploader.filename,imploader.etc
module = imploader.load_module(imploader.fullname)
break
if module is None:
raise ImportError