conda-forge 上 Python 包的 Noarch 变体包
我们为 conda-forge 上的 Python 包引入了 noarch 变体,这些包具有编译扩展,但带有纯 Python 参考实现,以便于新 Python 变体的早期采用者。
conda-forge 包一直是开箱即用的。当一个包默认关闭某些构建选项以减少依赖项时,我们启用了这些选项,以便为我们的用户提供最多的功能和性能。
在 Python 世界中,一些包是用 C/C++/Cython 编写的,以最大限度地提高性能。然而,这些包有时会有用 Python 编写的参考实现。Python 参考实现是检查 C/C++/Cython 代码与更简单的 Python 实现是否一致的好方法,并且对于 PyPy 等平台也很有用,在这些平台上,由于 PyPy 模拟 Python C/C++ API,C/C++/Cython 实现可能比 Python 参考实现慢。例如,对于 Cython 包,在构建 Cython wheel 本身时设置 CYTHON_NO_COMPILE
环境变量,它将使用 Python 参考实现。确定一个包是否具有 Python 参考实现的唯一方法是查看库的源代码,看看 extensions
是否是可选的。
为了支持像 PyPy 这样的平台,一些包构建带有编译扩展的 wheel,用于已知使用编译扩展性能更高的平台,但也为其他平台提供通用的纯 Python wheel。这也为新的 Python 版本和变体(如自由线程 Python 构建)提供了让这些 Python 版本的早期采用者使用这些包的方式。
在 conda-forge 上,我们通常有编译的 Python 包,但不提供参考实现。这意味着新 Python 版本的早期采用者需要等待由 @conda-forge/bot 团队管理的 conda-forge 机器人启动迁移并重建包。例如,自由线程 Python 3.13 构建仍然暂停,因为 conda-forge 已决定首先关注默认(启用 GIL)的 Python 3.13 构建,同时上游包致力于支持自由线程。另一个问题是,某些包在构建或测试时存在循环依赖关系,这需要一些手动处理。
我们一直在为某些 feedstock 添加 noarch: python
变体,以便编译的扩展具有更高的优先级,而纯 Python 扩展具有较低的优先级,这使得 conda 求解器在没有合适的编译变体可用时使用 noarch: python
变体。一个问题是 linter 可能不喜欢 noarch recipe 上的选择器。我们添加了一个选项
linter:
skip:
- lint_noarch_selectors
到 conda-forge.yml
,这将使 linter 跳过此警告/错误。
我们使用带有以下内容的 recipe/conda_build_config.yaml
构建这两个变体,
use_noarch:
- true # [linux64]
- false
然后在 recipe/meta.yaml
中,我们进行以下更改
build:
noarch: python # [use_noarch]
track_features: # [use_noarch]
- pyyaml_no_compile # [use_noarch]
requirements:
build:
- {{ compiler('c') }}
- {{ stdlib("c") }}
host:
- python # [not use_noarch]
- python {{ python_min }}.* # [use_noarch]
- setuptools
- pip
run:
- python # [not use_noarch]
- python >={{ python_min }}.* # [use_noarch]
- yaml
test:
requires:
- pip
- python {{ python_min }}.* # [use_noarch]
最后,在构建脚本中,我们使用环境变量 use_noarch
来设置一个选项,以强制扩展为纯 Python。对于 pyyaml,我们可以通过设置环境变量 PYYAML_NO_LIBYAML
来强制执行。一个 recipe/build.sh
可能看起来像,
if [[ "$use_noarch" == "true" ]]; then
export PYYAML_NO_LIBYAML=1
fi
$PYTHON -m pip install .
我们在此列出一些 PR 作为想要尝试的 conda-forge 维护者的参考。