【问题标题】:How to find "import name" of any package in Python?如何在 Python 中查找任何包的“导入名称”?
【发布时间】:2011-11-03 07:18:40
【问题描述】:

我想知道是否有任何可靠且一致的方法来获取 Python 包的“导入名称”/命名空间。例如;

; django-haystack
导入名称;干草堆

; ipython
导入名称; IPython

到目前为止,我知道,PyPi 不存储我使用 PyPiXmlRpc 检查过的信息。

我还尝试自动下载包、解压缩并挖掘 .egg-info,但有些包根本没有那个文件夹。

任何帮助将不胜感激,并将用于一个礼貌的小工具:)

【问题讨论】:

    标签: python namespaces pypi cheeseshop


    【解决方案1】:

    轮子

    我知道这是一个老问题,但是 wheel 包已经被发明了!由于 wheel 只是一个解压到 lib/site-packages 目录中的 zip 文件,因此检查 wheel 存档的内容可以为您提供顶级导入。

    >>> import zipfile
    >>> zf = zipfile.ZipFile('setuptools-35.0.2-py2.py3-none-any.whl')
    >>> top_level = set([x.split('/')[0] for x in zf.namelist()])
    >>> # filter out the .dist-info directory
    >>> top_level = [x for x in top_level if not x.endswith('.dist-info')]
    >>> top_level 
    ['setuptools', 'pkg_resources', 'easy_install.py']
    

    所以 setuptools 实际上为您提供了三个顶级导入!

    点下载

    pip 现在有一个下载命令,所以你可以简单地运行pip download setuptools(或任何你喜欢的包)然后检查它。

    反向查找

    不幸的是,我还没有找到一个简单的方法来转向另一个方向。也就是说,给定导入名称,包名称是什么。如果您正在查看一些示例代码,或者如果您使用预装了一堆软件包的 Anaconda 并且您想知道实际的软件包名称,这可能是一个问题。

    【讨论】:

    • 这很好,因为它不需要安装发行版来检索数据。谢谢!
    • 我有一个改进建议:输入[top_level_fname] = [x for x in zf.namelist() if x.endswith('top_level.txt')],然后直接使用zf.read(top_level_fname).decode('utf-8').splitlines()
    【解决方案2】:

    请注意,这里所说的包不是包,而是发行版。一个发行版可以包含零个或多个模块或包。这意味着分发包与包之间没有一对一的映射。

    我不确定有什么方法可以检测发行版将安装哪些模块和包,而不是实际安装它并检查新添加的包、模块和 pth 文件的文件系统更改。

    【讨论】:

    • 我明白了。如我所见,主要问题是发行版和包/包之间的关系。但我的问题必须有答案。我会找到最可靠和最一致的,并让你肯定知道。
    • 经过漫长的研究期后,我最终得到您的答案,即任何 Python 发行版都可能有一个或多个包,例如包本身,让我们说一个测试包旁边作为一个简单的例子。无论如何,我能够完成我的实验原型(pydoc.net),并希望能提供某种 API 来始终如一地涵盖这个问题。谢谢 Wichert。
    【解决方案3】:

    原则上,获取该信息所需的一切都在setup.py 中,应该在每个此类包中。该信息大致是 Distribution 对象的包、py_modules、ext_package 和 ext_modules 的联合。事实上,这里有一个小脚本模拟了distutils.core.setup,只是为了获取这些信息。

    import distutils.core
    distutils.core._setup_stop_after = "config"
    _real_setup = distutils.core.setup
    def _fake_setup(*args, **kwargs):
        global dist
        dist = _real_setup(*args, **kwargs)
    
    distutils.core.setup = _fake_setup
    
    import sys
    setup_file = sys.argv[1]
    sys.argv[:] = sys.argv[1:]
    import os.path
    os.chdir(os.path.dirname(setup_file))
    
    execfile(os.path.basename(setup_file))
    
    cat = lambda *seq: sum((i for i in seq if i is not None), [])
    pkgs = set(package.split('.')[0] for package
               in cat(dist.packages,
                      dist.py_modules,
                      [m.name for m in cat(dist.ext_modules)],
                      [m.name for m in cat(dist.ext_package)]))
    
    print "\n".join(pkgs)
    

    对于许多包来说,这就像一个魅力,但对于一个反例,请参阅numpy,它会因为 numpy 提供自己的 distutils 而中断,我看不出有什么明显的解决方法。

    【讨论】:

    • 我没有机会尝试,会尽快做和反馈。提前致谢!
    • 是的,它适用于许多软件包版本,但据我了解,它适用于模块查找器的逻辑,它为您提供所有已使用的模块,并且您可以从中获得高级命名空间。不幸的是,如果发行版使用了其他一些包,例如 test,它会提供多个命名空间;例如,检查 django-uni-form。顺便说一句,我只是稍微修改了您的脚本; gist.github.com/1176645
    • Python 应该在 PyPI 上设置“导入名称”字段!不可能那么痛苦……卡住了。
    • 说真的...我一直在绞尽脑汁思考如何从导入名称中获取分发名称。只是目前没有办法。我曾希望 setup.py 中的 provides 键能够提供此功能。我曾希望能够通过wiki.python.org/moin/PyPIXmlRpc 进行查询,但没有运气):
    猜你喜欢
    • 1970-01-01
    • 2012-09-10
    • 1970-01-01
    • 2015-07-14
    • 2022-12-01
    • 2018-08-16
    • 1970-01-01
    • 2022-10-15
    相关资源
    最近更新 更多