如何从 PyPi 包中提取依赖项

Posted

技术标签:

【中文标题】如何从 PyPi 包中提取依赖项【英文标题】:How to extract dependencies from a PyPi package 【发布时间】:2012-12-18 18:01:03 【问题描述】:

我的目标很简单,我想远程获取 PyPi 包的依赖,而不需要完全下载。

我似乎理解(阅读 pip 代码)解决依赖关系时的 pip 似乎在下载包后读取了鸡蛋...

还有其他方法吗?

【问题讨论】:

它要么在requirements.txt 中,要么在setup.py 中,也许你可以从repo 只下载一个文件,这取决于它的托管位置? (即 github 而不是 PyPi)Related Q 为什么不呢,但这需要特定于每个包,如果我不想为“任何”包手动做,那不会那么容易......跨度> 您可以在https://pypi.org/pypi/<package name>/json获取JSON格式的PyPI包元数据,例如pypi.org/pypi/tensorflow/json 【参考方案1】:

使用pipdeptree 查看已安装 PyPI 包的依赖关系。

安装:

pip install pipdeptree

然后运行:

pipdeptree

你会看到类似的东西:

Warning!!! Possible conflicting dependencies found:
* Mako==0.9.1 -> MarkupSafe [required: >=0.9.2, installed: 0.18]
  Jinja2==2.7.2 -> MarkupSafe [installed: 0.18]
------------------------------------------------------------------------
Lookupy==0.1
wsgiref==0.1.2
argparse==1.2.1
psycopg2==2.5.2
Flask-Script==0.6.6
  - Flask [installed: 0.10.1]
    - Werkzeug [required: >=0.7, installed: 0.9.4]
    - Jinja2 [required: >=2.4, installed: 2.7.2]
      - MarkupSafe [installed: 0.18]
    - itsdangerous [required: >=0.21, installed: 0.23]
alembic==0.6.2
  - SQLAlchemy [required: >=0.7.3, installed: 0.9.1]
  - Mako [installed: 0.9.1]
    - MarkupSafe [required: >=0.9.2, installed: 0.18]
ipython==2.0.0
slugify==0.0.1
redis==2.9.1

【讨论】:

够我用了【参考方案2】:

正如 jinghli 所指出的,目前还没有可靠的方法来远程获取任意 PyPi 包的依赖关系,而无需完全下载它。事实上,依赖关系有时取决于您的环境,因此在一般情况下需要像 Brian 那样执行 setup.py 代码的方法。

Python 生态系统处理依赖项的方式在 1990 年代开始演变,当时这个问题还没有被很好地理解。 PEP 508 -- Dependency specification for Python Software Packages 让我们走上了改善现状的道路,PEP 426 -- Metadata for Python Software Packages 2.0 中的“理想”草案方法可能会在未来进一步改善它,同时将 PyPI 重新实现为 Warehouse。

文档Python Dependency Resolution很好地描述了当前的情况。

PyPI 确实提供了一个json interface 来下载每个包的元数据。 info.requires_dist 对象包含所需包的名称列表以及可选的版本限制等。它经常丢失,但它是一个开始的地方。

例如Django (json) 表示:

"info": ... "requires_dist": [ "bcrypt; extra == 'bcrypt'", "argon2-cffi (>=16.1.0); extra == 'argon2'", "pytz" ], ...

【讨论】:

requires_dist 块不再显示来自 pypi 的链接 JSON :( 谢谢@AshBerlin。我更改了示例,因为 jupyter 不再有 requires_dist【参考方案3】:

我只是需要找到一种方法来做到这一点,这就是我想出的(从 pip 偷来的)。

def dist_metadata(setup_py):
    '''Get the dist object for setup.py file'''

    with open(setup_py) as f:
        d = f.read()

    try:
        # we have to do this with current globals else
        # imports will fail. secure? not really. A
        # problem? not really if your setup.py sources are 
        # trusted
        exec d in globals(), globals()
    except SystemExit:
        pass

    return distutils.core._setup_distribution

https://***.com/a/12505166/3332282 回答了为什么 exec 的咒语很微妙且难以正确。

【讨论】:

谢谢 - 棘手!但请注意,您需要在顶部使用import distutils,调用者将希望查看dist_metadata(setup_py).install_requires,它会返回一个包名称列表。这就留下了如何在不下载整个包的情况下获得setup.py 的问题,正如 OP 所要求的那样。 这不适用于 Python3。您需要将exec d in globals(), globals() 更改为exec(d, globals()) 并查看dist_metadata(setup_py).get_requires() 方法来获取要求。【参考方案4】:

很遗憾,pip 没有这个功能。 PyPI 上可用于包的元数据不包括有关依赖项的信息。

通常,您可以从项目网站的 README 文件中找到详细的依赖关系。

pip search 可以提供一些关于包的信息。它可以告诉你它是基于什么的。

$ pip search flask
Flask     - A microframework based on Werkzeug, Jinja2 and good intentions

【讨论】:

感谢您的信息。我真的很惊讶!我假设,根据 Debian/Ubuntu 包管理的工作原理,这将是以标准方式从包中获取的基本数据,因此像 pypi-data 这样的工具可以显示完整的依赖关系树。虽然我敢说这很复杂....

以上是关于如何从 PyPi 包中提取依赖项的主要内容,如果未能解决你的问题,请参考以下文章

JNA:本机库依赖项和JAR提取

如何强制 IntelliJ 中的 Maven 从本地 .m2 存储库中提取特定依赖项

如何从经过身份验证的私有 Artifactory PyPI 存储库中提取 Python 包?

如何从tar.gz包中,提取某些文件?

如何按索引从可变参数模板参数包中提取值?

如何从 msi 包中提取 ProductCode?