如何在Python中查找任何包的“导入名称”?

问题描述 投票:0回答:5

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

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

包装; ipython
导入名称; IPython

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

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

任何帮助将不胜感激,并将用于良好的小工具:)

python namespaces pypi cheeseshop
5个回答
10
投票

轮子

我知道这是一个老问题,但是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
(或任何您喜欢的包)然后检查它。

反向查找

从Python 3.10开始,有一个方便的功能可以进行反向查找(给出导入名称,包是什么)。官方官方文档在这里

from importlib.metadata import packages_distributions
packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'],  ...}

对于正向查找,您也可以简单地构建反向此字典。


9
投票

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

我不确定是否有一种方法可以检测发行版将安装哪些模块和软件包,除了实际安装它并内省新添加的软件包、模块和 pth 文件的文件系统更改之外。


5
投票

原则上,获取该信息所需的所有内容都在

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,而且我看不出有明显的解决方法。


2
投票

我的项目johnnydep有这个功能:

>>> from johnnydep import JohnnyDist
>>> dist = JohnnyDist("django-haystack")
>>> dist.import_names
['haystack']

请注意,一个发行版可能会提供多个导入名称:

>>> JohnnyDist("setuptools").import_names
['pkg_resources', 'setuptools']

或者根本没有:

>>> JohnnyDist("bs4").import_names
[]

0
投票

在搜索了大量信息后,终于找到了唯一符合我预期的东西。具有

python-dotenv
导入名称的
dotenv
包示例:

$ cat $(python -c "import pkg_resources; print(pkg_resources.get_distribution('python-dotenv').egg_info)")/top_level.txt
dotenv

(摘自这个答案

© www.soinside.com 2019 - 2024. All rights reserved.