imp.find_module的替代品?

时间:2011-04-21 08:16:49

标签: python namespaces importerror pylint

背景

我已经厌倦了在使用命名空间包并将代码库划分为单独的文件夹时,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的模块查找器非常聪明,不必完全匹配在这些路径中,无论如何都要使这种方法无法使用 -

Teary-eyed Plea

是否有替代find_modules会返回所有可能的匹配项或采取排除列表?我也对完全不同的解决方案持开放态度。最好不要手工修补python,但这不是不可能的 - 至少对于本地解决方案而言。

(警告:我正在运行python 2.6并且由于当前公司政策的原因无法升级,对p3k等的建议不会被标记为已被接受,除非它是唯一的答案。)

3 个答案:

答案 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)

之后: - 感谢pjeby提及pkgutil

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