我想知道是否有任何可靠且一致的方法来获取Python包的“导入名称”/命名空间。例如;
包装; django-haystack
导入名称;干草堆
或
包装; ipython
导入名称; IPython
到目前为止我知道,PyPi 不存储我用 PyPiXmlRpc 检查过的信息。
我还尝试自动下载包、解压并挖掘 .egg-info,但有些包根本没有该文件夹。
任何帮助将不胜感激,并将用于良好的小工具:)
我知道这是一个老问题,但是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'], ...}
对于正向查找,您也可以简单地构建反向此字典。
注意,这里所说的包不是包,而是一个 distribution。一个发行版可以包含零个或多个模块或包。这意味着发行版与包之间不存在一对一的映射。
我不确定是否有一种方法可以检测发行版将安装哪些模块和软件包,除了实际安装它并内省新添加的软件包、模块和 pth 文件的文件系统更改之外。
原则上,获取该信息所需的所有内容都在
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,而且我看不出有明显的解决方法。
我的项目johnnydep有这个功能:
>>> from johnnydep import JohnnyDist
>>> dist = JohnnyDist("django-haystack")
>>> dist.import_names
['haystack']
请注意,一个发行版可能会提供多个导入名称:
>>> JohnnyDist("setuptools").import_names
['pkg_resources', 'setuptools']
或者根本没有:
>>> JohnnyDist("bs4").import_names
[]
在搜索了大量信息后,终于找到了唯一符合我预期的东西。具有
python-dotenv
导入名称的 dotenv
包示例:
$ cat $(python -c "import pkg_resources; print(pkg_resources.get_distribution('python-dotenv').egg_info)")/top_level.txt
dotenv
(摘自这个答案)