我想知道是否有一种可靠且一致的方法来获取Python包的“导入名称”/命名空间。例如:
包:django-haystack
导入名称:haystack
或者
包:ipython
导入名称:IPython
据我所知,PyPi不存储该信息,我已经通过PyPiXmlRpc进行了检查。
我还尝试自动下载软件包、提取并查找.egg-info文件夹,但有些软件包根本没有这个文件夹。
任何帮助将不胜感激,并将用于一个有礼貌的小工具 :)
我想知道是否有一种可靠且一致的方法来获取Python包的“导入名称”/命名空间。例如:
包:django-haystack
导入名称:haystack
或者
包:ipython
导入名称:IPython
据我所知,PyPi不存储该信息,我已经通过PyPiXmlRpc进行了检查。
我还尝试自动下载软件包、提取并查找.egg-info文件夹,但有些软件包根本没有这个文件夹。
任何帮助将不胜感激,并将用于一个有礼貌的小工具 :)
我知道这是一个老问题,但是现在已经发明了轮子包!由于轮子只是一个被解压到 lib/site-packages 目录中的zip文件,因此检查轮子存档的内容可以提供顶级导入。
>>> 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并且想要知道实际的软件包名称,则可能会遇到问题。
原则上,获取该信息所需的一切都在每个该类软件包中应该有的setup.py
文件中。该信息大致为Distribution对象的packages、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,我无法找到明显的解决方法。
setup.py
中的 provides
键可以提供这个信息。我本来还想通过 https://wiki.python.org/moin/PyPIXmlRpc 来查询,但是没有成功 ): - d0c_s4vage我的项目约翰尼·德普有这个功能:
>>> 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
(taken from this answer)
[top_level_fname] = [x for x in zf.namelist() if x.endswith('top_level.txt')]
,然后只需使用zf.read(top_level_fname).decode('utf-8').splitlines()
。 - wim