防止软件包安装在旧的 Python 版本上

Posted

技术标签:

【中文标题】防止软件包安装在旧的 Python 版本上【英文标题】:Prevent package from being installed on old Python versions 【发布时间】:2017-07-03 11:17:56 【问题描述】:

当使用不受支持的 Python 版本时,我们可以在 setup.py 文件中添加什么来防止 pip 收集和尝试安装包?

例如magicstack 是一个使用 trove 分类器列出的项目:

Programming Language :: Python :: 3 :: Only

因此,如果 pip --version 与 python 2.7 相关联,我预计会出现以下行为:

$ pip install magicstack
Collecting magicstack
  Could not find a version that satisfies the requirement magicstack (from versions: )
No matching distribution found for magicstack

但实际行为是 pip 收集一个版本,下载它,尝试安装它,然后失败。还有其他仅限 Python3 的版本,例如 curio,它们实际上安装得很好 - 因为 setup.py 没有使用任何 Python 3 特定的东西 - 只有在使用某些 Python 3 语法时才会在导入时失败。而且我确定有些软件包可以安装,导入正常,并且可能只会在运行时失败!

以 pip 尊重的方式指定支持的 Python 版本的正确方法是什么?我找到了一种解决方法,包括只上传一个 wheel 文件,并拒绝上传 .tar .gz 发行版,但我很想知道正确的修复方法。


编辑: 如果 Python/os/architecture 不匹配,pip 如何知道 下载***分发?它只是使用.whl filename convention 还是有比幕后发生的更复杂的事情?我们能否以某种方式将元数据提供给源分发,以使 pip 对 .tar.gz 上传做正确的事情?

【问题讨论】:

我不知道这是 正确的 答案...但是如果 magicstack 是 python3 只是因为 setup.py 在 python2.x 上失败,那么它似乎像使这项工作的一种可能方法是强制您的 setup.py 在不适当的 python 版本上失败... 哈奇。如果 pip 绑定到不受支持的 Python 解释器,我根本不希望收集或下载包,更不用说通过执行 setup.py 尝试安装了。 Google 找到了一些 previous questions 并回答说让你的 setup.py 检查 Python 版本。 相关:packaging.python.org/guides/…,其中提到“虽然分类器列表通常用于声明项目支持的 Python 版本,但此信息仅用于在 PyPI 上搜索和浏览项目,不适用于安装项目。要实际限制可以安装项目的 Python 版本,请使用 python_requires 参数。" 相关:***.com/a/64386359/1959808 【参考方案1】:

pypi 上的magicstack 分布已损坏。它失败了,因为源代码分发不包含 magicstack 包,即使源代码分发的 setup.py 说它应该包含。

只要 pypi 包含源代码分发版(例如 .tar.gz.zip),pip 会在找不到匹配的二进制分发版(例如 .egg.whl)时下载您的版本蟒蛇/操作系统/架构。

一种选择是仅将二进制分发版上传到 PyPI(最好是 wheels)。另一种选择是检查setup.py 中的sys.version 以获取兼容版本,否则会引发异常。

【讨论】:

【参考方案2】:

有一个正确的方法可以做到这一点,但不幸的是 pip 仅在 9.0.0 版本(2016-11-02 发布)中开始支持它,因此使用旧版本 pip 的用户将继续下载软件包,不管怎样它们适用于哪个 Python 版本。

在您的setup.py 文件中,传递setup() 一个python_requires 参数,该参数将您的包支持的Python 版本列为PEP 440version specifier。例如,如果您的包仅适用于 Python 3+,请编写:

setup(
    ...
    python_requires='>=3',
    ...
)

如果您的包适用于 Python 3.3 及更高版本,但您还不愿意承诺支持 Python 4,请写:

setup(
    ...
    python_requires='~=3.3',
    ...
)

如果您的包适用于 Python 2.6、2.7 以及从 3.3 开始的所有 Python 3 版本,请编写:

setup(
    ...
    python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4',
    ...
)

等等。

完成此操作后,您需要将 setuptools 版本至少升级到 24.2.0,以便处理 python_requires 参数;早期版本只会忽略它并发出警告。之后构建的所有项目的 sdists 和***将包含相关的元数据,告诉 PyPI 告诉 pip 它们适用于哪些 Python 版本。

【讨论】:

@wim:python_requires 使用了什么版本说明符? 我已经上传了一个source distribution 用于在 pypi 上进行测试(请参阅here 以了解实现),它似乎正如您在 pypi 上所描述的那样工作。我只能在不同的索引上重现不正确的行为。我可能在devpi server 中遇到了一个错误,明天将进行更多调查... 查看这里了解更多有用信息:python3statement.org/practicalities 我的问题确实是由于索引中的错误(旧版本的 devpi 服务器无法正确提供 python_requires 元数据 - 我相信它在当前版本中已解决)。 我认为值得一提的是,该项目必须使用pip3 install [-e] 安装(而不是“直接”使用python3 setup.py install),如下所述:python3statement.org/practicalities

以上是关于防止软件包安装在旧的 Python 版本上的主要内容,如果未能解决你的问题,请参考以下文章

在旧版 OS X 上的 OS X10.6.4 上开发的软件包的兼容性问题

python使用pip 18以上版本离线安装package

单机ASM替换存储和主机

ubuntu下命令怎么看查看pip版本

在旧 Mac (10.6.8) 上安装 git

API 是不是应该在 API 响应中发回 UI 层文本/数据以允许在旧的 android/ios 应用程序版本中随时更改?