imp.find_module 的替代品?

发布于 2024-11-02 12:25:40 字数 1215 浏览 6 评论 0原文

背景

当您使用命名空间包并将代码库划分为单独的文件夹时,我已经厌倦了 pylint 无法导入文件的问题。因此,我开始深入研究 astNG 源代码,该源代码已被确定为问题的根源(请参阅错误报告 8796 on astng)。问题的核心似乎是在查找导入的过程中使用了 python 自己的imp.find_module。

发生的情况是,导入的第一个(子)包 - import abc 中的 a - 被馈送到带有 Nonefind_module代码>路径。无论返回的路径是什么,都会被输入到查找循环中的下一个遍中的 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 等的建议不会被标记为已接受,除非它是唯一的答案。)

Background

I've grown tired of the issue with pylint not being able to import files when you use namespace packages and divide your code-base into separate folders. As such I started digging into the astNG source-code which has been identified as the source of the trouble (see bugreport 8796 on astng). At the heart of the issue seems to be the use of pythons own imp.find_module in the process of finding imports.

What happens is that the import's first (sub)package - a in import a.b.c - is fed to find_module with a None path. Whatever path comes back is then fed into find_module the next pass in the look up loop where you try to find b in the previous example.

Pseudo-code from 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)

The Problem

This is what's broken: you only get the first best hit from find_module, which may or may not have your subpackages in it. If you DON'T find the subpackages, you have no way to back out and try the next one.

I tried explicitly using sys.path instead of None, so that the result could be removed from the path list and a second attempt be made, but python's module finder is clever enough that there doesn't have to be an exact match in the paths, making this approach unusable - to the best of my knowledge anyway.

Teary-eyed Plea

Is there an alternative to find_modules which will return ALL possible matches or take an exclude list? I'm also open to completely different solutions. Preferably not patching python by hand, but it wouldn't be impossible - at least for a local solution.

(Caveat emptor: I'm running python 2.6 and for reasons of current company policy can't upgrade, suggestions for p3k etc won't get marked as accepted unless it's the only answer.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等往事风中吹 2024-11-09 12:25:40

从Python 2.5开始,正确的方法是使用 pkgutil.iter_modules() (对于平面列表)或 pkgutil.walk_packages()< /a> (对于子包树)。两者都与命名空间包完全兼容。

例如,如果我只想查找“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 上的所有模块;有关详细信息,请参阅上面链接的文档。

Since Python 2.5, the right way to do this is with pkgutil.iter_modules() (for a flat list) or pkgutil.walk_packages() (for a subpackage tree). Both are fully compatible with namespace packages.

For example, if I wanted to find just the subpackages/submodules of 'jmb', I would do:

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

You can also use iter_modules or walk_packages to walk all the modules on sys.path; see the docs linked above for details.

じее 2024-11-09 12:25:40

我也厌倦了 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__

这不是很精致,但只处理顶级命名空间包。

I've grown tired of this limitation in PyLint too.

I don't know a replacement for imp.find_modules(), but I think I found another way to deal with namespace packages in PyLint. See my comment on the bug report you linked to (http://www.logilab.org/ticket/8796).

The idea is to use pkg_resources to find namespace packages. Here's my addition to logilab.common.modutils._module_file(), just after 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__

This not very refined and only handles top-level namespace packages though.

清引 2024-11-09 12:25:40

警告+免责声明:尚未测试!

之前:

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

warning + disclaimer: not tested yet!

before:

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)

after: - thanks pjeby for mentioning 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文